diff --git a/db/db.go b/db/db.go index 99ee487..21dfcd2 100644 --- a/db/db.go +++ b/db/db.go @@ -9,6 +9,7 @@ import ( "polaris/ent/downloadclients" "polaris/ent/episode" "polaris/ent/history" + "polaris/ent/importlist" "polaris/ent/indexers" "polaris/ent/media" "polaris/ent/schema" @@ -580,3 +581,25 @@ func (c *Client) UpdateEpisodeTargetFile(id int, filename string) error { func (c *Client) GetSeasonEpisodes(mediaId, seasonNum int) ([]*ent.Episode, error) { return c.ent.Episode.Query().Where(episode.MediaID(mediaId), episode.SeasonNumber(seasonNum)).All(context.Background()) } + +func (c *Client) GetAllImportLists() ([]*ent.ImportList, error) { + return c.ent.ImportList.Query().All(context.Background()) +} + +func (c *Client) AddImportlist(il *ent.ImportList) error { + count, err := c.ent.ImportList.Query().Where(importlist.Name(il.Name)).Count(context.Background()) + if err != nil { + return err + } + if count > 0 { + //edit exist record + return c.ent.ImportList.Update().Where(importlist.Name(il.Name)). + SetURL(il.URL).SetQulity(il.Qulity).SetType(il.Type).SetStorageID(il.StorageID).Exec(context.Background()) + } + return c.ent.ImportList.Create().SetName(il.Name).SetURL(il.URL).SetQulity(il.Qulity).SetStorageID(il.StorageID). + SetType(il.Type).Exec(context.Background()) +} + +func (c *Client) DeleteImportlist(id int) error { + return c.ent.ImportList.DeleteOneID(id).Exec(context.TODO()) +} \ No newline at end of file diff --git a/ent/client.go b/ent/client.go index 2134b0a..97d1f55 100644 --- a/ent/client.go +++ b/ent/client.go @@ -14,6 +14,7 @@ import ( "polaris/ent/downloadclients" "polaris/ent/episode" "polaris/ent/history" + "polaris/ent/importlist" "polaris/ent/indexers" "polaris/ent/media" "polaris/ent/notificationclient" @@ -37,6 +38,8 @@ type Client struct { Episode *EpisodeClient // History is the client for interacting with the History builders. History *HistoryClient + // ImportList is the client for interacting with the ImportList builders. + ImportList *ImportListClient // Indexers is the client for interacting with the Indexers builders. Indexers *IndexersClient // Media is the client for interacting with the Media builders. @@ -61,6 +64,7 @@ func (c *Client) init() { c.DownloadClients = NewDownloadClientsClient(c.config) c.Episode = NewEpisodeClient(c.config) c.History = NewHistoryClient(c.config) + c.ImportList = NewImportListClient(c.config) c.Indexers = NewIndexersClient(c.config) c.Media = NewMediaClient(c.config) c.NotificationClient = NewNotificationClientClient(c.config) @@ -161,6 +165,7 @@ func (c *Client) Tx(ctx context.Context) (*Tx, error) { DownloadClients: NewDownloadClientsClient(cfg), Episode: NewEpisodeClient(cfg), History: NewHistoryClient(cfg), + ImportList: NewImportListClient(cfg), Indexers: NewIndexersClient(cfg), Media: NewMediaClient(cfg), NotificationClient: NewNotificationClientClient(cfg), @@ -188,6 +193,7 @@ func (c *Client) BeginTx(ctx context.Context, opts *sql.TxOptions) (*Tx, error) DownloadClients: NewDownloadClientsClient(cfg), Episode: NewEpisodeClient(cfg), History: NewHistoryClient(cfg), + ImportList: NewImportListClient(cfg), Indexers: NewIndexersClient(cfg), Media: NewMediaClient(cfg), NotificationClient: NewNotificationClientClient(cfg), @@ -222,7 +228,7 @@ func (c *Client) Close() error { // In order to add hooks to a specific client, call: `client.Node.Use(...)`. func (c *Client) Use(hooks ...Hook) { for _, n := range []interface{ Use(...Hook) }{ - c.DownloadClients, c.Episode, c.History, c.Indexers, c.Media, + c.DownloadClients, c.Episode, c.History, c.ImportList, c.Indexers, c.Media, c.NotificationClient, c.Settings, c.Storage, } { n.Use(hooks...) @@ -233,7 +239,7 @@ func (c *Client) Use(hooks ...Hook) { // In order to add interceptors to a specific client, call: `client.Node.Intercept(...)`. func (c *Client) Intercept(interceptors ...Interceptor) { for _, n := range []interface{ Intercept(...Interceptor) }{ - c.DownloadClients, c.Episode, c.History, c.Indexers, c.Media, + c.DownloadClients, c.Episode, c.History, c.ImportList, c.Indexers, c.Media, c.NotificationClient, c.Settings, c.Storage, } { n.Intercept(interceptors...) @@ -249,6 +255,8 @@ func (c *Client) Mutate(ctx context.Context, m Mutation) (Value, error) { return c.Episode.mutate(ctx, m) case *HistoryMutation: return c.History.mutate(ctx, m) + case *ImportListMutation: + return c.ImportList.mutate(ctx, m) case *IndexersMutation: return c.Indexers.mutate(ctx, m) case *MediaMutation: @@ -679,6 +687,139 @@ func (c *HistoryClient) mutate(ctx context.Context, m *HistoryMutation) (Value, } } +// ImportListClient is a client for the ImportList schema. +type ImportListClient struct { + config +} + +// NewImportListClient returns a client for the ImportList from the given config. +func NewImportListClient(c config) *ImportListClient { + return &ImportListClient{config: c} +} + +// Use adds a list of mutation hooks to the hooks stack. +// A call to `Use(f, g, h)` equals to `importlist.Hooks(f(g(h())))`. +func (c *ImportListClient) Use(hooks ...Hook) { + c.hooks.ImportList = append(c.hooks.ImportList, hooks...) +} + +// Intercept adds a list of query interceptors to the interceptors stack. +// A call to `Intercept(f, g, h)` equals to `importlist.Intercept(f(g(h())))`. +func (c *ImportListClient) Intercept(interceptors ...Interceptor) { + c.inters.ImportList = append(c.inters.ImportList, interceptors...) +} + +// Create returns a builder for creating a ImportList entity. +func (c *ImportListClient) Create() *ImportListCreate { + mutation := newImportListMutation(c.config, OpCreate) + return &ImportListCreate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// CreateBulk returns a builder for creating a bulk of ImportList entities. +func (c *ImportListClient) CreateBulk(builders ...*ImportListCreate) *ImportListCreateBulk { + return &ImportListCreateBulk{config: c.config, builders: builders} +} + +// MapCreateBulk creates a bulk creation builder from the given slice. For each item in the slice, the function creates +// a builder and applies setFunc on it. +func (c *ImportListClient) MapCreateBulk(slice any, setFunc func(*ImportListCreate, int)) *ImportListCreateBulk { + rv := reflect.ValueOf(slice) + if rv.Kind() != reflect.Slice { + return &ImportListCreateBulk{err: fmt.Errorf("calling to ImportListClient.MapCreateBulk with wrong type %T, need slice", slice)} + } + builders := make([]*ImportListCreate, rv.Len()) + for i := 0; i < rv.Len(); i++ { + builders[i] = c.Create() + setFunc(builders[i], i) + } + return &ImportListCreateBulk{config: c.config, builders: builders} +} + +// Update returns an update builder for ImportList. +func (c *ImportListClient) Update() *ImportListUpdate { + mutation := newImportListMutation(c.config, OpUpdate) + return &ImportListUpdate{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOne returns an update builder for the given entity. +func (c *ImportListClient) UpdateOne(il *ImportList) *ImportListUpdateOne { + mutation := newImportListMutation(c.config, OpUpdateOne, withImportList(il)) + return &ImportListUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// UpdateOneID returns an update builder for the given id. +func (c *ImportListClient) UpdateOneID(id int) *ImportListUpdateOne { + mutation := newImportListMutation(c.config, OpUpdateOne, withImportListID(id)) + return &ImportListUpdateOne{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// Delete returns a delete builder for ImportList. +func (c *ImportListClient) Delete() *ImportListDelete { + mutation := newImportListMutation(c.config, OpDelete) + return &ImportListDelete{config: c.config, hooks: c.Hooks(), mutation: mutation} +} + +// DeleteOne returns a builder for deleting the given entity. +func (c *ImportListClient) DeleteOne(il *ImportList) *ImportListDeleteOne { + return c.DeleteOneID(il.ID) +} + +// DeleteOneID returns a builder for deleting the given entity by its id. +func (c *ImportListClient) DeleteOneID(id int) *ImportListDeleteOne { + builder := c.Delete().Where(importlist.ID(id)) + builder.mutation.id = &id + builder.mutation.op = OpDeleteOne + return &ImportListDeleteOne{builder} +} + +// Query returns a query builder for ImportList. +func (c *ImportListClient) Query() *ImportListQuery { + return &ImportListQuery{ + config: c.config, + ctx: &QueryContext{Type: TypeImportList}, + inters: c.Interceptors(), + } +} + +// Get returns a ImportList entity by its id. +func (c *ImportListClient) Get(ctx context.Context, id int) (*ImportList, error) { + return c.Query().Where(importlist.ID(id)).Only(ctx) +} + +// GetX is like Get, but panics if an error occurs. +func (c *ImportListClient) GetX(ctx context.Context, id int) *ImportList { + obj, err := c.Get(ctx, id) + if err != nil { + panic(err) + } + return obj +} + +// Hooks returns the client hooks. +func (c *ImportListClient) Hooks() []Hook { + return c.hooks.ImportList +} + +// Interceptors returns the client interceptors. +func (c *ImportListClient) Interceptors() []Interceptor { + return c.inters.ImportList +} + +func (c *ImportListClient) mutate(ctx context.Context, m *ImportListMutation) (Value, error) { + switch m.Op() { + case OpCreate: + return (&ImportListCreate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdate: + return (&ImportListUpdate{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpUpdateOne: + return (&ImportListUpdateOne{config: c.config, hooks: c.Hooks(), mutation: m}).Save(ctx) + case OpDelete, OpDeleteOne: + return (&ImportListDelete{config: c.config, hooks: c.Hooks(), mutation: m}).Exec(ctx) + default: + return nil, fmt.Errorf("ent: unknown ImportList mutation op: %q", m.Op()) + } +} + // IndexersClient is a client for the Indexers schema. type IndexersClient struct { config @@ -1363,11 +1504,11 @@ func (c *StorageClient) mutate(ctx context.Context, m *StorageMutation) (Value, // hooks and interceptors per client, for fast access. type ( hooks struct { - DownloadClients, Episode, History, Indexers, Media, NotificationClient, - Settings, Storage []ent.Hook + DownloadClients, Episode, History, ImportList, Indexers, Media, + NotificationClient, Settings, Storage []ent.Hook } inters struct { - DownloadClients, Episode, History, Indexers, Media, NotificationClient, - Settings, Storage []ent.Interceptor + DownloadClients, Episode, History, ImportList, Indexers, Media, + NotificationClient, Settings, Storage []ent.Interceptor } ) diff --git a/ent/ent.go b/ent/ent.go index a3fa936..b1a4dba 100644 --- a/ent/ent.go +++ b/ent/ent.go @@ -9,6 +9,7 @@ import ( "polaris/ent/downloadclients" "polaris/ent/episode" "polaris/ent/history" + "polaris/ent/importlist" "polaris/ent/indexers" "polaris/ent/media" "polaris/ent/notificationclient" @@ -83,6 +84,7 @@ func checkColumn(table, column string) error { downloadclients.Table: downloadclients.ValidColumn, episode.Table: episode.ValidColumn, history.Table: history.ValidColumn, + importlist.Table: importlist.ValidColumn, indexers.Table: indexers.ValidColumn, media.Table: media.ValidColumn, notificationclient.Table: notificationclient.ValidColumn, diff --git a/ent/hook/hook.go b/ent/hook/hook.go index 40f95df..0ad076b 100644 --- a/ent/hook/hook.go +++ b/ent/hook/hook.go @@ -44,6 +44,18 @@ func (f HistoryFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, err return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.HistoryMutation", m) } +// The ImportListFunc type is an adapter to allow the use of ordinary +// function as ImportList mutator. +type ImportListFunc func(context.Context, *ent.ImportListMutation) (ent.Value, error) + +// Mutate calls f(ctx, m). +func (f ImportListFunc) Mutate(ctx context.Context, m ent.Mutation) (ent.Value, error) { + if mv, ok := m.(*ent.ImportListMutation); ok { + return f(ctx, mv) + } + return nil, fmt.Errorf("unexpected mutation type %T. expect *ent.ImportListMutation", m) +} + // The IndexersFunc type is an adapter to allow the use of ordinary // function as Indexers mutator. type IndexersFunc func(context.Context, *ent.IndexersMutation) (ent.Value, error) diff --git a/ent/importlist.go b/ent/importlist.go new file mode 100644 index 0000000..cf5f468 --- /dev/null +++ b/ent/importlist.go @@ -0,0 +1,164 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "encoding/json" + "fmt" + "polaris/ent/importlist" + "polaris/ent/schema" + "strings" + + "entgo.io/ent" + "entgo.io/ent/dialect/sql" +) + +// ImportList is the model entity for the ImportList schema. +type ImportList struct { + config `json:"-"` + // ID of the ent. + ID int `json:"id,omitempty"` + // Name holds the value of the "name" field. + Name string `json:"name,omitempty"` + // Type holds the value of the "type" field. + Type importlist.Type `json:"type,omitempty"` + // URL holds the value of the "url" field. + URL string `json:"url,omitempty"` + // Qulity holds the value of the "qulity" field. + Qulity string `json:"qulity,omitempty"` + // StorageID holds the value of the "storage_id" field. + StorageID int `json:"storage_id,omitempty"` + // Settings holds the value of the "settings" field. + Settings schema.ImportListSettings `json:"settings,omitempty"` + selectValues sql.SelectValues +} + +// scanValues returns the types for scanning values from sql.Rows. +func (*ImportList) scanValues(columns []string) ([]any, error) { + values := make([]any, len(columns)) + for i := range columns { + switch columns[i] { + case importlist.FieldSettings: + values[i] = new([]byte) + case importlist.FieldID, importlist.FieldStorageID: + values[i] = new(sql.NullInt64) + case importlist.FieldName, importlist.FieldType, importlist.FieldURL, importlist.FieldQulity: + values[i] = new(sql.NullString) + default: + values[i] = new(sql.UnknownType) + } + } + return values, nil +} + +// assignValues assigns the values that were returned from sql.Rows (after scanning) +// to the ImportList fields. +func (il *ImportList) assignValues(columns []string, values []any) error { + if m, n := len(values), len(columns); m < n { + return fmt.Errorf("mismatch number of scan values: %d != %d", m, n) + } + for i := range columns { + switch columns[i] { + case importlist.FieldID: + value, ok := values[i].(*sql.NullInt64) + if !ok { + return fmt.Errorf("unexpected type %T for field id", value) + } + il.ID = int(value.Int64) + case importlist.FieldName: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field name", values[i]) + } else if value.Valid { + il.Name = value.String + } + case importlist.FieldType: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field type", values[i]) + } else if value.Valid { + il.Type = importlist.Type(value.String) + } + case importlist.FieldURL: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field url", values[i]) + } else if value.Valid { + il.URL = value.String + } + case importlist.FieldQulity: + if value, ok := values[i].(*sql.NullString); !ok { + return fmt.Errorf("unexpected type %T for field qulity", values[i]) + } else if value.Valid { + il.Qulity = value.String + } + case importlist.FieldStorageID: + if value, ok := values[i].(*sql.NullInt64); !ok { + return fmt.Errorf("unexpected type %T for field storage_id", values[i]) + } else if value.Valid { + il.StorageID = int(value.Int64) + } + case importlist.FieldSettings: + if value, ok := values[i].(*[]byte); !ok { + return fmt.Errorf("unexpected type %T for field settings", values[i]) + } else if value != nil && len(*value) > 0 { + if err := json.Unmarshal(*value, &il.Settings); err != nil { + return fmt.Errorf("unmarshal field settings: %w", err) + } + } + default: + il.selectValues.Set(columns[i], values[i]) + } + } + return nil +} + +// Value returns the ent.Value that was dynamically selected and assigned to the ImportList. +// This includes values selected through modifiers, order, etc. +func (il *ImportList) Value(name string) (ent.Value, error) { + return il.selectValues.Get(name) +} + +// Update returns a builder for updating this ImportList. +// Note that you need to call ImportList.Unwrap() before calling this method if this ImportList +// was returned from a transaction, and the transaction was committed or rolled back. +func (il *ImportList) Update() *ImportListUpdateOne { + return NewImportListClient(il.config).UpdateOne(il) +} + +// Unwrap unwraps the ImportList entity that was returned from a transaction after it was closed, +// so that all future queries will be executed through the driver which created the transaction. +func (il *ImportList) Unwrap() *ImportList { + _tx, ok := il.config.driver.(*txDriver) + if !ok { + panic("ent: ImportList is not a transactional entity") + } + il.config.driver = _tx.drv + return il +} + +// String implements the fmt.Stringer. +func (il *ImportList) String() string { + var builder strings.Builder + builder.WriteString("ImportList(") + builder.WriteString(fmt.Sprintf("id=%v, ", il.ID)) + builder.WriteString("name=") + builder.WriteString(il.Name) + builder.WriteString(", ") + builder.WriteString("type=") + builder.WriteString(fmt.Sprintf("%v", il.Type)) + builder.WriteString(", ") + builder.WriteString("url=") + builder.WriteString(il.URL) + builder.WriteString(", ") + builder.WriteString("qulity=") + builder.WriteString(il.Qulity) + builder.WriteString(", ") + builder.WriteString("storage_id=") + builder.WriteString(fmt.Sprintf("%v", il.StorageID)) + builder.WriteString(", ") + builder.WriteString("settings=") + builder.WriteString(fmt.Sprintf("%v", il.Settings)) + builder.WriteByte(')') + return builder.String() +} + +// ImportLists is a parsable slice of ImportList. +type ImportLists []*ImportList diff --git a/ent/importlist/importlist.go b/ent/importlist/importlist.go new file mode 100644 index 0000000..591e4eb --- /dev/null +++ b/ent/importlist/importlist.go @@ -0,0 +1,107 @@ +// Code generated by ent, DO NOT EDIT. + +package importlist + +import ( + "fmt" + + "entgo.io/ent/dialect/sql" +) + +const ( + // Label holds the string label denoting the importlist type in the database. + Label = "import_list" + // FieldID holds the string denoting the id field in the database. + FieldID = "id" + // FieldName holds the string denoting the name field in the database. + FieldName = "name" + // FieldType holds the string denoting the type field in the database. + FieldType = "type" + // FieldURL holds the string denoting the url field in the database. + FieldURL = "url" + // FieldQulity holds the string denoting the qulity field in the database. + FieldQulity = "qulity" + // FieldStorageID holds the string denoting the storage_id field in the database. + FieldStorageID = "storage_id" + // FieldSettings holds the string denoting the settings field in the database. + FieldSettings = "settings" + // Table holds the table name of the importlist in the database. + Table = "import_lists" +) + +// Columns holds all SQL columns for importlist fields. +var Columns = []string{ + FieldID, + FieldName, + FieldType, + FieldURL, + FieldQulity, + FieldStorageID, + FieldSettings, +} + +// ValidColumn reports if the column name is valid (part of the table columns). +func ValidColumn(column string) bool { + for i := range Columns { + if column == Columns[i] { + return true + } + } + return false +} + +// Type defines the type for the "type" enum field. +type Type string + +// Type values. +const ( + TypePlex Type = "plex" + TypeDoulist Type = "doulist" +) + +func (_type Type) String() string { + return string(_type) +} + +// TypeValidator is a validator for the "type" field enum values. It is called by the builders before save. +func TypeValidator(_type Type) error { + switch _type { + case TypePlex, TypeDoulist: + return nil + default: + return fmt.Errorf("importlist: invalid enum value for type field: %q", _type) + } +} + +// OrderOption defines the ordering options for the ImportList queries. +type OrderOption func(*sql.Selector) + +// ByID orders the results by the id field. +func ByID(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldID, opts...).ToFunc() +} + +// ByName orders the results by the name field. +func ByName(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldName, opts...).ToFunc() +} + +// ByType orders the results by the type field. +func ByType(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldType, opts...).ToFunc() +} + +// ByURL orders the results by the url field. +func ByURL(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldURL, opts...).ToFunc() +} + +// ByQulity orders the results by the qulity field. +func ByQulity(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldQulity, opts...).ToFunc() +} + +// ByStorageID orders the results by the storage_id field. +func ByStorageID(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldStorageID, opts...).ToFunc() +} diff --git a/ent/importlist/where.go b/ent/importlist/where.go new file mode 100644 index 0000000..5c3a3f5 --- /dev/null +++ b/ent/importlist/where.go @@ -0,0 +1,364 @@ +// Code generated by ent, DO NOT EDIT. + +package importlist + +import ( + "polaris/ent/predicate" + + "entgo.io/ent/dialect/sql" +) + +// ID filters vertices based on their ID field. +func ID(id int) predicate.ImportList { + return predicate.ImportList(sql.FieldEQ(FieldID, id)) +} + +// IDEQ applies the EQ predicate on the ID field. +func IDEQ(id int) predicate.ImportList { + return predicate.ImportList(sql.FieldEQ(FieldID, id)) +} + +// IDNEQ applies the NEQ predicate on the ID field. +func IDNEQ(id int) predicate.ImportList { + return predicate.ImportList(sql.FieldNEQ(FieldID, id)) +} + +// IDIn applies the In predicate on the ID field. +func IDIn(ids ...int) predicate.ImportList { + return predicate.ImportList(sql.FieldIn(FieldID, ids...)) +} + +// IDNotIn applies the NotIn predicate on the ID field. +func IDNotIn(ids ...int) predicate.ImportList { + return predicate.ImportList(sql.FieldNotIn(FieldID, ids...)) +} + +// IDGT applies the GT predicate on the ID field. +func IDGT(id int) predicate.ImportList { + return predicate.ImportList(sql.FieldGT(FieldID, id)) +} + +// IDGTE applies the GTE predicate on the ID field. +func IDGTE(id int) predicate.ImportList { + return predicate.ImportList(sql.FieldGTE(FieldID, id)) +} + +// IDLT applies the LT predicate on the ID field. +func IDLT(id int) predicate.ImportList { + return predicate.ImportList(sql.FieldLT(FieldID, id)) +} + +// IDLTE applies the LTE predicate on the ID field. +func IDLTE(id int) predicate.ImportList { + return predicate.ImportList(sql.FieldLTE(FieldID, id)) +} + +// Name applies equality check predicate on the "name" field. It's identical to NameEQ. +func Name(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldEQ(FieldName, v)) +} + +// URL applies equality check predicate on the "url" field. It's identical to URLEQ. +func URL(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldEQ(FieldURL, v)) +} + +// Qulity applies equality check predicate on the "qulity" field. It's identical to QulityEQ. +func Qulity(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldEQ(FieldQulity, v)) +} + +// StorageID applies equality check predicate on the "storage_id" field. It's identical to StorageIDEQ. +func StorageID(v int) predicate.ImportList { + return predicate.ImportList(sql.FieldEQ(FieldStorageID, v)) +} + +// NameEQ applies the EQ predicate on the "name" field. +func NameEQ(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldEQ(FieldName, v)) +} + +// NameNEQ applies the NEQ predicate on the "name" field. +func NameNEQ(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldNEQ(FieldName, v)) +} + +// NameIn applies the In predicate on the "name" field. +func NameIn(vs ...string) predicate.ImportList { + return predicate.ImportList(sql.FieldIn(FieldName, vs...)) +} + +// NameNotIn applies the NotIn predicate on the "name" field. +func NameNotIn(vs ...string) predicate.ImportList { + return predicate.ImportList(sql.FieldNotIn(FieldName, vs...)) +} + +// NameGT applies the GT predicate on the "name" field. +func NameGT(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldGT(FieldName, v)) +} + +// NameGTE applies the GTE predicate on the "name" field. +func NameGTE(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldGTE(FieldName, v)) +} + +// NameLT applies the LT predicate on the "name" field. +func NameLT(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldLT(FieldName, v)) +} + +// NameLTE applies the LTE predicate on the "name" field. +func NameLTE(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldLTE(FieldName, v)) +} + +// NameContains applies the Contains predicate on the "name" field. +func NameContains(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldContains(FieldName, v)) +} + +// NameHasPrefix applies the HasPrefix predicate on the "name" field. +func NameHasPrefix(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldHasPrefix(FieldName, v)) +} + +// NameHasSuffix applies the HasSuffix predicate on the "name" field. +func NameHasSuffix(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldHasSuffix(FieldName, v)) +} + +// NameEqualFold applies the EqualFold predicate on the "name" field. +func NameEqualFold(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldEqualFold(FieldName, v)) +} + +// NameContainsFold applies the ContainsFold predicate on the "name" field. +func NameContainsFold(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldContainsFold(FieldName, v)) +} + +// TypeEQ applies the EQ predicate on the "type" field. +func TypeEQ(v Type) predicate.ImportList { + return predicate.ImportList(sql.FieldEQ(FieldType, v)) +} + +// TypeNEQ applies the NEQ predicate on the "type" field. +func TypeNEQ(v Type) predicate.ImportList { + return predicate.ImportList(sql.FieldNEQ(FieldType, v)) +} + +// TypeIn applies the In predicate on the "type" field. +func TypeIn(vs ...Type) predicate.ImportList { + return predicate.ImportList(sql.FieldIn(FieldType, vs...)) +} + +// TypeNotIn applies the NotIn predicate on the "type" field. +func TypeNotIn(vs ...Type) predicate.ImportList { + return predicate.ImportList(sql.FieldNotIn(FieldType, vs...)) +} + +// URLEQ applies the EQ predicate on the "url" field. +func URLEQ(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldEQ(FieldURL, v)) +} + +// URLNEQ applies the NEQ predicate on the "url" field. +func URLNEQ(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldNEQ(FieldURL, v)) +} + +// URLIn applies the In predicate on the "url" field. +func URLIn(vs ...string) predicate.ImportList { + return predicate.ImportList(sql.FieldIn(FieldURL, vs...)) +} + +// URLNotIn applies the NotIn predicate on the "url" field. +func URLNotIn(vs ...string) predicate.ImportList { + return predicate.ImportList(sql.FieldNotIn(FieldURL, vs...)) +} + +// URLGT applies the GT predicate on the "url" field. +func URLGT(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldGT(FieldURL, v)) +} + +// URLGTE applies the GTE predicate on the "url" field. +func URLGTE(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldGTE(FieldURL, v)) +} + +// URLLT applies the LT predicate on the "url" field. +func URLLT(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldLT(FieldURL, v)) +} + +// URLLTE applies the LTE predicate on the "url" field. +func URLLTE(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldLTE(FieldURL, v)) +} + +// URLContains applies the Contains predicate on the "url" field. +func URLContains(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldContains(FieldURL, v)) +} + +// URLHasPrefix applies the HasPrefix predicate on the "url" field. +func URLHasPrefix(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldHasPrefix(FieldURL, v)) +} + +// URLHasSuffix applies the HasSuffix predicate on the "url" field. +func URLHasSuffix(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldHasSuffix(FieldURL, v)) +} + +// URLIsNil applies the IsNil predicate on the "url" field. +func URLIsNil() predicate.ImportList { + return predicate.ImportList(sql.FieldIsNull(FieldURL)) +} + +// URLNotNil applies the NotNil predicate on the "url" field. +func URLNotNil() predicate.ImportList { + return predicate.ImportList(sql.FieldNotNull(FieldURL)) +} + +// URLEqualFold applies the EqualFold predicate on the "url" field. +func URLEqualFold(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldEqualFold(FieldURL, v)) +} + +// URLContainsFold applies the ContainsFold predicate on the "url" field. +func URLContainsFold(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldContainsFold(FieldURL, v)) +} + +// QulityEQ applies the EQ predicate on the "qulity" field. +func QulityEQ(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldEQ(FieldQulity, v)) +} + +// QulityNEQ applies the NEQ predicate on the "qulity" field. +func QulityNEQ(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldNEQ(FieldQulity, v)) +} + +// QulityIn applies the In predicate on the "qulity" field. +func QulityIn(vs ...string) predicate.ImportList { + return predicate.ImportList(sql.FieldIn(FieldQulity, vs...)) +} + +// QulityNotIn applies the NotIn predicate on the "qulity" field. +func QulityNotIn(vs ...string) predicate.ImportList { + return predicate.ImportList(sql.FieldNotIn(FieldQulity, vs...)) +} + +// QulityGT applies the GT predicate on the "qulity" field. +func QulityGT(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldGT(FieldQulity, v)) +} + +// QulityGTE applies the GTE predicate on the "qulity" field. +func QulityGTE(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldGTE(FieldQulity, v)) +} + +// QulityLT applies the LT predicate on the "qulity" field. +func QulityLT(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldLT(FieldQulity, v)) +} + +// QulityLTE applies the LTE predicate on the "qulity" field. +func QulityLTE(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldLTE(FieldQulity, v)) +} + +// QulityContains applies the Contains predicate on the "qulity" field. +func QulityContains(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldContains(FieldQulity, v)) +} + +// QulityHasPrefix applies the HasPrefix predicate on the "qulity" field. +func QulityHasPrefix(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldHasPrefix(FieldQulity, v)) +} + +// QulityHasSuffix applies the HasSuffix predicate on the "qulity" field. +func QulityHasSuffix(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldHasSuffix(FieldQulity, v)) +} + +// QulityEqualFold applies the EqualFold predicate on the "qulity" field. +func QulityEqualFold(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldEqualFold(FieldQulity, v)) +} + +// QulityContainsFold applies the ContainsFold predicate on the "qulity" field. +func QulityContainsFold(v string) predicate.ImportList { + return predicate.ImportList(sql.FieldContainsFold(FieldQulity, v)) +} + +// StorageIDEQ applies the EQ predicate on the "storage_id" field. +func StorageIDEQ(v int) predicate.ImportList { + return predicate.ImportList(sql.FieldEQ(FieldStorageID, v)) +} + +// StorageIDNEQ applies the NEQ predicate on the "storage_id" field. +func StorageIDNEQ(v int) predicate.ImportList { + return predicate.ImportList(sql.FieldNEQ(FieldStorageID, v)) +} + +// StorageIDIn applies the In predicate on the "storage_id" field. +func StorageIDIn(vs ...int) predicate.ImportList { + return predicate.ImportList(sql.FieldIn(FieldStorageID, vs...)) +} + +// StorageIDNotIn applies the NotIn predicate on the "storage_id" field. +func StorageIDNotIn(vs ...int) predicate.ImportList { + return predicate.ImportList(sql.FieldNotIn(FieldStorageID, vs...)) +} + +// StorageIDGT applies the GT predicate on the "storage_id" field. +func StorageIDGT(v int) predicate.ImportList { + return predicate.ImportList(sql.FieldGT(FieldStorageID, v)) +} + +// StorageIDGTE applies the GTE predicate on the "storage_id" field. +func StorageIDGTE(v int) predicate.ImportList { + return predicate.ImportList(sql.FieldGTE(FieldStorageID, v)) +} + +// StorageIDLT applies the LT predicate on the "storage_id" field. +func StorageIDLT(v int) predicate.ImportList { + return predicate.ImportList(sql.FieldLT(FieldStorageID, v)) +} + +// StorageIDLTE applies the LTE predicate on the "storage_id" field. +func StorageIDLTE(v int) predicate.ImportList { + return predicate.ImportList(sql.FieldLTE(FieldStorageID, v)) +} + +// SettingsIsNil applies the IsNil predicate on the "settings" field. +func SettingsIsNil() predicate.ImportList { + return predicate.ImportList(sql.FieldIsNull(FieldSettings)) +} + +// SettingsNotNil applies the NotNil predicate on the "settings" field. +func SettingsNotNil() predicate.ImportList { + return predicate.ImportList(sql.FieldNotNull(FieldSettings)) +} + +// And groups predicates with the AND operator between them. +func And(predicates ...predicate.ImportList) predicate.ImportList { + return predicate.ImportList(sql.AndPredicates(predicates...)) +} + +// Or groups predicates with the OR operator between them. +func Or(predicates ...predicate.ImportList) predicate.ImportList { + return predicate.ImportList(sql.OrPredicates(predicates...)) +} + +// Not applies the not operator on the given predicate. +func Not(p predicate.ImportList) predicate.ImportList { + return predicate.ImportList(sql.NotPredicates(p)) +} diff --git a/ent/importlist_create.go b/ent/importlist_create.go new file mode 100644 index 0000000..1e748e2 --- /dev/null +++ b/ent/importlist_create.go @@ -0,0 +1,264 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "polaris/ent/importlist" + "polaris/ent/schema" + + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" +) + +// ImportListCreate is the builder for creating a ImportList entity. +type ImportListCreate struct { + config + mutation *ImportListMutation + hooks []Hook +} + +// SetName sets the "name" field. +func (ilc *ImportListCreate) SetName(s string) *ImportListCreate { + ilc.mutation.SetName(s) + return ilc +} + +// SetType sets the "type" field. +func (ilc *ImportListCreate) SetType(i importlist.Type) *ImportListCreate { + ilc.mutation.SetType(i) + return ilc +} + +// SetURL sets the "url" field. +func (ilc *ImportListCreate) SetURL(s string) *ImportListCreate { + ilc.mutation.SetURL(s) + return ilc +} + +// SetNillableURL sets the "url" field if the given value is not nil. +func (ilc *ImportListCreate) SetNillableURL(s *string) *ImportListCreate { + if s != nil { + ilc.SetURL(*s) + } + return ilc +} + +// SetQulity sets the "qulity" field. +func (ilc *ImportListCreate) SetQulity(s string) *ImportListCreate { + ilc.mutation.SetQulity(s) + return ilc +} + +// SetStorageID sets the "storage_id" field. +func (ilc *ImportListCreate) SetStorageID(i int) *ImportListCreate { + ilc.mutation.SetStorageID(i) + return ilc +} + +// SetSettings sets the "settings" field. +func (ilc *ImportListCreate) SetSettings(sls schema.ImportListSettings) *ImportListCreate { + ilc.mutation.SetSettings(sls) + return ilc +} + +// SetNillableSettings sets the "settings" field if the given value is not nil. +func (ilc *ImportListCreate) SetNillableSettings(sls *schema.ImportListSettings) *ImportListCreate { + if sls != nil { + ilc.SetSettings(*sls) + } + return ilc +} + +// Mutation returns the ImportListMutation object of the builder. +func (ilc *ImportListCreate) Mutation() *ImportListMutation { + return ilc.mutation +} + +// Save creates the ImportList in the database. +func (ilc *ImportListCreate) Save(ctx context.Context) (*ImportList, error) { + return withHooks(ctx, ilc.sqlSave, ilc.mutation, ilc.hooks) +} + +// SaveX calls Save and panics if Save returns an error. +func (ilc *ImportListCreate) SaveX(ctx context.Context) *ImportList { + v, err := ilc.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (ilc *ImportListCreate) Exec(ctx context.Context) error { + _, err := ilc.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (ilc *ImportListCreate) ExecX(ctx context.Context) { + if err := ilc.Exec(ctx); err != nil { + panic(err) + } +} + +// check runs all checks and user-defined validators on the builder. +func (ilc *ImportListCreate) check() error { + if _, ok := ilc.mutation.Name(); !ok { + return &ValidationError{Name: "name", err: errors.New(`ent: missing required field "ImportList.name"`)} + } + if _, ok := ilc.mutation.GetType(); !ok { + return &ValidationError{Name: "type", err: errors.New(`ent: missing required field "ImportList.type"`)} + } + if v, ok := ilc.mutation.GetType(); ok { + if err := importlist.TypeValidator(v); err != nil { + return &ValidationError{Name: "type", err: fmt.Errorf(`ent: validator failed for field "ImportList.type": %w`, err)} + } + } + if _, ok := ilc.mutation.Qulity(); !ok { + return &ValidationError{Name: "qulity", err: errors.New(`ent: missing required field "ImportList.qulity"`)} + } + if _, ok := ilc.mutation.StorageID(); !ok { + return &ValidationError{Name: "storage_id", err: errors.New(`ent: missing required field "ImportList.storage_id"`)} + } + return nil +} + +func (ilc *ImportListCreate) sqlSave(ctx context.Context) (*ImportList, error) { + if err := ilc.check(); err != nil { + return nil, err + } + _node, _spec := ilc.createSpec() + if err := sqlgraph.CreateNode(ctx, ilc.driver, _spec); err != nil { + if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + id := _spec.ID.Value.(int64) + _node.ID = int(id) + ilc.mutation.id = &_node.ID + ilc.mutation.done = true + return _node, nil +} + +func (ilc *ImportListCreate) createSpec() (*ImportList, *sqlgraph.CreateSpec) { + var ( + _node = &ImportList{config: ilc.config} + _spec = sqlgraph.NewCreateSpec(importlist.Table, sqlgraph.NewFieldSpec(importlist.FieldID, field.TypeInt)) + ) + if value, ok := ilc.mutation.Name(); ok { + _spec.SetField(importlist.FieldName, field.TypeString, value) + _node.Name = value + } + if value, ok := ilc.mutation.GetType(); ok { + _spec.SetField(importlist.FieldType, field.TypeEnum, value) + _node.Type = value + } + if value, ok := ilc.mutation.URL(); ok { + _spec.SetField(importlist.FieldURL, field.TypeString, value) + _node.URL = value + } + if value, ok := ilc.mutation.Qulity(); ok { + _spec.SetField(importlist.FieldQulity, field.TypeString, value) + _node.Qulity = value + } + if value, ok := ilc.mutation.StorageID(); ok { + _spec.SetField(importlist.FieldStorageID, field.TypeInt, value) + _node.StorageID = value + } + if value, ok := ilc.mutation.Settings(); ok { + _spec.SetField(importlist.FieldSettings, field.TypeJSON, value) + _node.Settings = value + } + return _node, _spec +} + +// ImportListCreateBulk is the builder for creating many ImportList entities in bulk. +type ImportListCreateBulk struct { + config + err error + builders []*ImportListCreate +} + +// Save creates the ImportList entities in the database. +func (ilcb *ImportListCreateBulk) Save(ctx context.Context) ([]*ImportList, error) { + if ilcb.err != nil { + return nil, ilcb.err + } + specs := make([]*sqlgraph.CreateSpec, len(ilcb.builders)) + nodes := make([]*ImportList, len(ilcb.builders)) + mutators := make([]Mutator, len(ilcb.builders)) + for i := range ilcb.builders { + func(i int, root context.Context) { + builder := ilcb.builders[i] + var mut Mutator = MutateFunc(func(ctx context.Context, m Mutation) (Value, error) { + mutation, ok := m.(*ImportListMutation) + if !ok { + return nil, fmt.Errorf("unexpected mutation type %T", m) + } + if err := builder.check(); err != nil { + return nil, err + } + builder.mutation = mutation + var err error + nodes[i], specs[i] = builder.createSpec() + if i < len(mutators)-1 { + _, err = mutators[i+1].Mutate(root, ilcb.builders[i+1].mutation) + } else { + spec := &sqlgraph.BatchCreateSpec{Nodes: specs} + // Invoke the actual operation on the latest mutation in the chain. + if err = sqlgraph.BatchCreate(ctx, ilcb.driver, spec); err != nil { + if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + } + } + if err != nil { + return nil, err + } + mutation.id = &nodes[i].ID + if specs[i].ID.Value != nil { + id := specs[i].ID.Value.(int64) + nodes[i].ID = int(id) + } + mutation.done = true + return nodes[i], nil + }) + for i := len(builder.hooks) - 1; i >= 0; i-- { + mut = builder.hooks[i](mut) + } + mutators[i] = mut + }(i, ctx) + } + if len(mutators) > 0 { + if _, err := mutators[0].Mutate(ctx, ilcb.builders[0].mutation); err != nil { + return nil, err + } + } + return nodes, nil +} + +// SaveX is like Save, but panics if an error occurs. +func (ilcb *ImportListCreateBulk) SaveX(ctx context.Context) []*ImportList { + v, err := ilcb.Save(ctx) + if err != nil { + panic(err) + } + return v +} + +// Exec executes the query. +func (ilcb *ImportListCreateBulk) Exec(ctx context.Context) error { + _, err := ilcb.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (ilcb *ImportListCreateBulk) ExecX(ctx context.Context) { + if err := ilcb.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/ent/importlist_delete.go b/ent/importlist_delete.go new file mode 100644 index 0000000..f77a250 --- /dev/null +++ b/ent/importlist_delete.go @@ -0,0 +1,88 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "polaris/ent/importlist" + "polaris/ent/predicate" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" +) + +// ImportListDelete is the builder for deleting a ImportList entity. +type ImportListDelete struct { + config + hooks []Hook + mutation *ImportListMutation +} + +// Where appends a list predicates to the ImportListDelete builder. +func (ild *ImportListDelete) Where(ps ...predicate.ImportList) *ImportListDelete { + ild.mutation.Where(ps...) + return ild +} + +// Exec executes the deletion query and returns how many vertices were deleted. +func (ild *ImportListDelete) Exec(ctx context.Context) (int, error) { + return withHooks(ctx, ild.sqlExec, ild.mutation, ild.hooks) +} + +// ExecX is like Exec, but panics if an error occurs. +func (ild *ImportListDelete) ExecX(ctx context.Context) int { + n, err := ild.Exec(ctx) + if err != nil { + panic(err) + } + return n +} + +func (ild *ImportListDelete) sqlExec(ctx context.Context) (int, error) { + _spec := sqlgraph.NewDeleteSpec(importlist.Table, sqlgraph.NewFieldSpec(importlist.FieldID, field.TypeInt)) + if ps := ild.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + affected, err := sqlgraph.DeleteNodes(ctx, ild.driver, _spec) + if err != nil && sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + ild.mutation.done = true + return affected, err +} + +// ImportListDeleteOne is the builder for deleting a single ImportList entity. +type ImportListDeleteOne struct { + ild *ImportListDelete +} + +// Where appends a list predicates to the ImportListDelete builder. +func (ildo *ImportListDeleteOne) Where(ps ...predicate.ImportList) *ImportListDeleteOne { + ildo.ild.mutation.Where(ps...) + return ildo +} + +// Exec executes the deletion query. +func (ildo *ImportListDeleteOne) Exec(ctx context.Context) error { + n, err := ildo.ild.Exec(ctx) + switch { + case err != nil: + return err + case n == 0: + return &NotFoundError{importlist.Label} + default: + return nil + } +} + +// ExecX is like Exec, but panics if an error occurs. +func (ildo *ImportListDeleteOne) ExecX(ctx context.Context) { + if err := ildo.Exec(ctx); err != nil { + panic(err) + } +} diff --git a/ent/importlist_query.go b/ent/importlist_query.go new file mode 100644 index 0000000..23dc547 --- /dev/null +++ b/ent/importlist_query.go @@ -0,0 +1,526 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "fmt" + "math" + "polaris/ent/importlist" + "polaris/ent/predicate" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" +) + +// ImportListQuery is the builder for querying ImportList entities. +type ImportListQuery struct { + config + ctx *QueryContext + order []importlist.OrderOption + inters []Interceptor + predicates []predicate.ImportList + // intermediate query (i.e. traversal path). + sql *sql.Selector + path func(context.Context) (*sql.Selector, error) +} + +// Where adds a new predicate for the ImportListQuery builder. +func (ilq *ImportListQuery) Where(ps ...predicate.ImportList) *ImportListQuery { + ilq.predicates = append(ilq.predicates, ps...) + return ilq +} + +// Limit the number of records to be returned by this query. +func (ilq *ImportListQuery) Limit(limit int) *ImportListQuery { + ilq.ctx.Limit = &limit + return ilq +} + +// Offset to start from. +func (ilq *ImportListQuery) Offset(offset int) *ImportListQuery { + ilq.ctx.Offset = &offset + return ilq +} + +// Unique configures the query builder to filter duplicate records on query. +// By default, unique is set to true, and can be disabled using this method. +func (ilq *ImportListQuery) Unique(unique bool) *ImportListQuery { + ilq.ctx.Unique = &unique + return ilq +} + +// Order specifies how the records should be ordered. +func (ilq *ImportListQuery) Order(o ...importlist.OrderOption) *ImportListQuery { + ilq.order = append(ilq.order, o...) + return ilq +} + +// First returns the first ImportList entity from the query. +// Returns a *NotFoundError when no ImportList was found. +func (ilq *ImportListQuery) First(ctx context.Context) (*ImportList, error) { + nodes, err := ilq.Limit(1).All(setContextOp(ctx, ilq.ctx, "First")) + if err != nil { + return nil, err + } + if len(nodes) == 0 { + return nil, &NotFoundError{importlist.Label} + } + return nodes[0], nil +} + +// FirstX is like First, but panics if an error occurs. +func (ilq *ImportListQuery) FirstX(ctx context.Context) *ImportList { + node, err := ilq.First(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return node +} + +// FirstID returns the first ImportList ID from the query. +// Returns a *NotFoundError when no ImportList ID was found. +func (ilq *ImportListQuery) FirstID(ctx context.Context) (id int, err error) { + var ids []int + if ids, err = ilq.Limit(1).IDs(setContextOp(ctx, ilq.ctx, "FirstID")); err != nil { + return + } + if len(ids) == 0 { + err = &NotFoundError{importlist.Label} + return + } + return ids[0], nil +} + +// FirstIDX is like FirstID, but panics if an error occurs. +func (ilq *ImportListQuery) FirstIDX(ctx context.Context) int { + id, err := ilq.FirstID(ctx) + if err != nil && !IsNotFound(err) { + panic(err) + } + return id +} + +// Only returns a single ImportList entity found by the query, ensuring it only returns one. +// Returns a *NotSingularError when more than one ImportList entity is found. +// Returns a *NotFoundError when no ImportList entities are found. +func (ilq *ImportListQuery) Only(ctx context.Context) (*ImportList, error) { + nodes, err := ilq.Limit(2).All(setContextOp(ctx, ilq.ctx, "Only")) + if err != nil { + return nil, err + } + switch len(nodes) { + case 1: + return nodes[0], nil + case 0: + return nil, &NotFoundError{importlist.Label} + default: + return nil, &NotSingularError{importlist.Label} + } +} + +// OnlyX is like Only, but panics if an error occurs. +func (ilq *ImportListQuery) OnlyX(ctx context.Context) *ImportList { + node, err := ilq.Only(ctx) + if err != nil { + panic(err) + } + return node +} + +// OnlyID is like Only, but returns the only ImportList ID in the query. +// Returns a *NotSingularError when more than one ImportList ID is found. +// Returns a *NotFoundError when no entities are found. +func (ilq *ImportListQuery) OnlyID(ctx context.Context) (id int, err error) { + var ids []int + if ids, err = ilq.Limit(2).IDs(setContextOp(ctx, ilq.ctx, "OnlyID")); err != nil { + return + } + switch len(ids) { + case 1: + id = ids[0] + case 0: + err = &NotFoundError{importlist.Label} + default: + err = &NotSingularError{importlist.Label} + } + return +} + +// OnlyIDX is like OnlyID, but panics if an error occurs. +func (ilq *ImportListQuery) OnlyIDX(ctx context.Context) int { + id, err := ilq.OnlyID(ctx) + if err != nil { + panic(err) + } + return id +} + +// All executes the query and returns a list of ImportLists. +func (ilq *ImportListQuery) All(ctx context.Context) ([]*ImportList, error) { + ctx = setContextOp(ctx, ilq.ctx, "All") + if err := ilq.prepareQuery(ctx); err != nil { + return nil, err + } + qr := querierAll[[]*ImportList, *ImportListQuery]() + return withInterceptors[[]*ImportList](ctx, ilq, qr, ilq.inters) +} + +// AllX is like All, but panics if an error occurs. +func (ilq *ImportListQuery) AllX(ctx context.Context) []*ImportList { + nodes, err := ilq.All(ctx) + if err != nil { + panic(err) + } + return nodes +} + +// IDs executes the query and returns a list of ImportList IDs. +func (ilq *ImportListQuery) IDs(ctx context.Context) (ids []int, err error) { + if ilq.ctx.Unique == nil && ilq.path != nil { + ilq.Unique(true) + } + ctx = setContextOp(ctx, ilq.ctx, "IDs") + if err = ilq.Select(importlist.FieldID).Scan(ctx, &ids); err != nil { + return nil, err + } + return ids, nil +} + +// IDsX is like IDs, but panics if an error occurs. +func (ilq *ImportListQuery) IDsX(ctx context.Context) []int { + ids, err := ilq.IDs(ctx) + if err != nil { + panic(err) + } + return ids +} + +// Count returns the count of the given query. +func (ilq *ImportListQuery) Count(ctx context.Context) (int, error) { + ctx = setContextOp(ctx, ilq.ctx, "Count") + if err := ilq.prepareQuery(ctx); err != nil { + return 0, err + } + return withInterceptors[int](ctx, ilq, querierCount[*ImportListQuery](), ilq.inters) +} + +// CountX is like Count, but panics if an error occurs. +func (ilq *ImportListQuery) CountX(ctx context.Context) int { + count, err := ilq.Count(ctx) + if err != nil { + panic(err) + } + return count +} + +// Exist returns true if the query has elements in the graph. +func (ilq *ImportListQuery) Exist(ctx context.Context) (bool, error) { + ctx = setContextOp(ctx, ilq.ctx, "Exist") + switch _, err := ilq.FirstID(ctx); { + case IsNotFound(err): + return false, nil + case err != nil: + return false, fmt.Errorf("ent: check existence: %w", err) + default: + return true, nil + } +} + +// ExistX is like Exist, but panics if an error occurs. +func (ilq *ImportListQuery) ExistX(ctx context.Context) bool { + exist, err := ilq.Exist(ctx) + if err != nil { + panic(err) + } + return exist +} + +// Clone returns a duplicate of the ImportListQuery builder, including all associated steps. It can be +// used to prepare common query builders and use them differently after the clone is made. +func (ilq *ImportListQuery) Clone() *ImportListQuery { + if ilq == nil { + return nil + } + return &ImportListQuery{ + config: ilq.config, + ctx: ilq.ctx.Clone(), + order: append([]importlist.OrderOption{}, ilq.order...), + inters: append([]Interceptor{}, ilq.inters...), + predicates: append([]predicate.ImportList{}, ilq.predicates...), + // clone intermediate query. + sql: ilq.sql.Clone(), + path: ilq.path, + } +} + +// GroupBy is used to group vertices by one or more fields/columns. +// It is often used with aggregate functions, like: count, max, mean, min, sum. +// +// Example: +// +// var v []struct { +// Name string `json:"name,omitempty"` +// Count int `json:"count,omitempty"` +// } +// +// client.ImportList.Query(). +// GroupBy(importlist.FieldName). +// Aggregate(ent.Count()). +// Scan(ctx, &v) +func (ilq *ImportListQuery) GroupBy(field string, fields ...string) *ImportListGroupBy { + ilq.ctx.Fields = append([]string{field}, fields...) + grbuild := &ImportListGroupBy{build: ilq} + grbuild.flds = &ilq.ctx.Fields + grbuild.label = importlist.Label + grbuild.scan = grbuild.Scan + return grbuild +} + +// Select allows the selection one or more fields/columns for the given query, +// instead of selecting all fields in the entity. +// +// Example: +// +// var v []struct { +// Name string `json:"name,omitempty"` +// } +// +// client.ImportList.Query(). +// Select(importlist.FieldName). +// Scan(ctx, &v) +func (ilq *ImportListQuery) Select(fields ...string) *ImportListSelect { + ilq.ctx.Fields = append(ilq.ctx.Fields, fields...) + sbuild := &ImportListSelect{ImportListQuery: ilq} + sbuild.label = importlist.Label + sbuild.flds, sbuild.scan = &ilq.ctx.Fields, sbuild.Scan + return sbuild +} + +// Aggregate returns a ImportListSelect configured with the given aggregations. +func (ilq *ImportListQuery) Aggregate(fns ...AggregateFunc) *ImportListSelect { + return ilq.Select().Aggregate(fns...) +} + +func (ilq *ImportListQuery) prepareQuery(ctx context.Context) error { + for _, inter := range ilq.inters { + if inter == nil { + return fmt.Errorf("ent: uninitialized interceptor (forgotten import ent/runtime?)") + } + if trv, ok := inter.(Traverser); ok { + if err := trv.Traverse(ctx, ilq); err != nil { + return err + } + } + } + for _, f := range ilq.ctx.Fields { + if !importlist.ValidColumn(f) { + return &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + } + if ilq.path != nil { + prev, err := ilq.path(ctx) + if err != nil { + return err + } + ilq.sql = prev + } + return nil +} + +func (ilq *ImportListQuery) sqlAll(ctx context.Context, hooks ...queryHook) ([]*ImportList, error) { + var ( + nodes = []*ImportList{} + _spec = ilq.querySpec() + ) + _spec.ScanValues = func(columns []string) ([]any, error) { + return (*ImportList).scanValues(nil, columns) + } + _spec.Assign = func(columns []string, values []any) error { + node := &ImportList{config: ilq.config} + nodes = append(nodes, node) + return node.assignValues(columns, values) + } + for i := range hooks { + hooks[i](ctx, _spec) + } + if err := sqlgraph.QueryNodes(ctx, ilq.driver, _spec); err != nil { + return nil, err + } + if len(nodes) == 0 { + return nodes, nil + } + return nodes, nil +} + +func (ilq *ImportListQuery) sqlCount(ctx context.Context) (int, error) { + _spec := ilq.querySpec() + _spec.Node.Columns = ilq.ctx.Fields + if len(ilq.ctx.Fields) > 0 { + _spec.Unique = ilq.ctx.Unique != nil && *ilq.ctx.Unique + } + return sqlgraph.CountNodes(ctx, ilq.driver, _spec) +} + +func (ilq *ImportListQuery) querySpec() *sqlgraph.QuerySpec { + _spec := sqlgraph.NewQuerySpec(importlist.Table, importlist.Columns, sqlgraph.NewFieldSpec(importlist.FieldID, field.TypeInt)) + _spec.From = ilq.sql + if unique := ilq.ctx.Unique; unique != nil { + _spec.Unique = *unique + } else if ilq.path != nil { + _spec.Unique = true + } + if fields := ilq.ctx.Fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, importlist.FieldID) + for i := range fields { + if fields[i] != importlist.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, fields[i]) + } + } + } + if ps := ilq.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if limit := ilq.ctx.Limit; limit != nil { + _spec.Limit = *limit + } + if offset := ilq.ctx.Offset; offset != nil { + _spec.Offset = *offset + } + if ps := ilq.order; len(ps) > 0 { + _spec.Order = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + return _spec +} + +func (ilq *ImportListQuery) sqlQuery(ctx context.Context) *sql.Selector { + builder := sql.Dialect(ilq.driver.Dialect()) + t1 := builder.Table(importlist.Table) + columns := ilq.ctx.Fields + if len(columns) == 0 { + columns = importlist.Columns + } + selector := builder.Select(t1.Columns(columns...)...).From(t1) + if ilq.sql != nil { + selector = ilq.sql + selector.Select(selector.Columns(columns...)...) + } + if ilq.ctx.Unique != nil && *ilq.ctx.Unique { + selector.Distinct() + } + for _, p := range ilq.predicates { + p(selector) + } + for _, p := range ilq.order { + p(selector) + } + if offset := ilq.ctx.Offset; offset != nil { + // limit is mandatory for offset clause. We start + // with default value, and override it below if needed. + selector.Offset(*offset).Limit(math.MaxInt32) + } + if limit := ilq.ctx.Limit; limit != nil { + selector.Limit(*limit) + } + return selector +} + +// ImportListGroupBy is the group-by builder for ImportList entities. +type ImportListGroupBy struct { + selector + build *ImportListQuery +} + +// Aggregate adds the given aggregation functions to the group-by query. +func (ilgb *ImportListGroupBy) Aggregate(fns ...AggregateFunc) *ImportListGroupBy { + ilgb.fns = append(ilgb.fns, fns...) + return ilgb +} + +// Scan applies the selector query and scans the result into the given value. +func (ilgb *ImportListGroupBy) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, ilgb.build.ctx, "GroupBy") + if err := ilgb.build.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*ImportListQuery, *ImportListGroupBy](ctx, ilgb.build, ilgb, ilgb.build.inters, v) +} + +func (ilgb *ImportListGroupBy) sqlScan(ctx context.Context, root *ImportListQuery, v any) error { + selector := root.sqlQuery(ctx).Select() + aggregation := make([]string, 0, len(ilgb.fns)) + for _, fn := range ilgb.fns { + aggregation = append(aggregation, fn(selector)) + } + if len(selector.SelectedColumns()) == 0 { + columns := make([]string, 0, len(*ilgb.flds)+len(ilgb.fns)) + for _, f := range *ilgb.flds { + columns = append(columns, selector.C(f)) + } + columns = append(columns, aggregation...) + selector.Select(columns...) + } + selector.GroupBy(selector.Columns(*ilgb.flds...)...) + if err := selector.Err(); err != nil { + return err + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := ilgb.build.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} + +// ImportListSelect is the builder for selecting fields of ImportList entities. +type ImportListSelect struct { + *ImportListQuery + selector +} + +// Aggregate adds the given aggregation functions to the selector query. +func (ils *ImportListSelect) Aggregate(fns ...AggregateFunc) *ImportListSelect { + ils.fns = append(ils.fns, fns...) + return ils +} + +// Scan applies the selector query and scans the result into the given value. +func (ils *ImportListSelect) Scan(ctx context.Context, v any) error { + ctx = setContextOp(ctx, ils.ctx, "Select") + if err := ils.prepareQuery(ctx); err != nil { + return err + } + return scanWithInterceptors[*ImportListQuery, *ImportListSelect](ctx, ils.ImportListQuery, ils, ils.inters, v) +} + +func (ils *ImportListSelect) sqlScan(ctx context.Context, root *ImportListQuery, v any) error { + selector := root.sqlQuery(ctx) + aggregation := make([]string, 0, len(ils.fns)) + for _, fn := range ils.fns { + aggregation = append(aggregation, fn(selector)) + } + switch n := len(*ils.selector.flds); { + case n == 0 && len(aggregation) > 0: + selector.Select(aggregation...) + case n != 0 && len(aggregation) > 0: + selector.AppendSelect(aggregation...) + } + rows := &sql.Rows{} + query, args := selector.Query() + if err := ils.driver.Query(ctx, query, args, rows); err != nil { + return err + } + defer rows.Close() + return sql.ScanSlice(rows, v) +} diff --git a/ent/importlist_update.go b/ent/importlist_update.go new file mode 100644 index 0000000..93ad5ae --- /dev/null +++ b/ent/importlist_update.go @@ -0,0 +1,462 @@ +// Code generated by ent, DO NOT EDIT. + +package ent + +import ( + "context" + "errors" + "fmt" + "polaris/ent/importlist" + "polaris/ent/predicate" + "polaris/ent/schema" + + "entgo.io/ent/dialect/sql" + "entgo.io/ent/dialect/sql/sqlgraph" + "entgo.io/ent/schema/field" +) + +// ImportListUpdate is the builder for updating ImportList entities. +type ImportListUpdate struct { + config + hooks []Hook + mutation *ImportListMutation +} + +// Where appends a list predicates to the ImportListUpdate builder. +func (ilu *ImportListUpdate) Where(ps ...predicate.ImportList) *ImportListUpdate { + ilu.mutation.Where(ps...) + return ilu +} + +// SetName sets the "name" field. +func (ilu *ImportListUpdate) SetName(s string) *ImportListUpdate { + ilu.mutation.SetName(s) + return ilu +} + +// SetNillableName sets the "name" field if the given value is not nil. +func (ilu *ImportListUpdate) SetNillableName(s *string) *ImportListUpdate { + if s != nil { + ilu.SetName(*s) + } + return ilu +} + +// SetType sets the "type" field. +func (ilu *ImportListUpdate) SetType(i importlist.Type) *ImportListUpdate { + ilu.mutation.SetType(i) + return ilu +} + +// SetNillableType sets the "type" field if the given value is not nil. +func (ilu *ImportListUpdate) SetNillableType(i *importlist.Type) *ImportListUpdate { + if i != nil { + ilu.SetType(*i) + } + return ilu +} + +// SetURL sets the "url" field. +func (ilu *ImportListUpdate) SetURL(s string) *ImportListUpdate { + ilu.mutation.SetURL(s) + return ilu +} + +// SetNillableURL sets the "url" field if the given value is not nil. +func (ilu *ImportListUpdate) SetNillableURL(s *string) *ImportListUpdate { + if s != nil { + ilu.SetURL(*s) + } + return ilu +} + +// ClearURL clears the value of the "url" field. +func (ilu *ImportListUpdate) ClearURL() *ImportListUpdate { + ilu.mutation.ClearURL() + return ilu +} + +// SetQulity sets the "qulity" field. +func (ilu *ImportListUpdate) SetQulity(s string) *ImportListUpdate { + ilu.mutation.SetQulity(s) + return ilu +} + +// SetNillableQulity sets the "qulity" field if the given value is not nil. +func (ilu *ImportListUpdate) SetNillableQulity(s *string) *ImportListUpdate { + if s != nil { + ilu.SetQulity(*s) + } + return ilu +} + +// SetStorageID sets the "storage_id" field. +func (ilu *ImportListUpdate) SetStorageID(i int) *ImportListUpdate { + ilu.mutation.ResetStorageID() + ilu.mutation.SetStorageID(i) + return ilu +} + +// SetNillableStorageID sets the "storage_id" field if the given value is not nil. +func (ilu *ImportListUpdate) SetNillableStorageID(i *int) *ImportListUpdate { + if i != nil { + ilu.SetStorageID(*i) + } + return ilu +} + +// AddStorageID adds i to the "storage_id" field. +func (ilu *ImportListUpdate) AddStorageID(i int) *ImportListUpdate { + ilu.mutation.AddStorageID(i) + return ilu +} + +// SetSettings sets the "settings" field. +func (ilu *ImportListUpdate) SetSettings(sls schema.ImportListSettings) *ImportListUpdate { + ilu.mutation.SetSettings(sls) + return ilu +} + +// SetNillableSettings sets the "settings" field if the given value is not nil. +func (ilu *ImportListUpdate) SetNillableSettings(sls *schema.ImportListSettings) *ImportListUpdate { + if sls != nil { + ilu.SetSettings(*sls) + } + return ilu +} + +// ClearSettings clears the value of the "settings" field. +func (ilu *ImportListUpdate) ClearSettings() *ImportListUpdate { + ilu.mutation.ClearSettings() + return ilu +} + +// Mutation returns the ImportListMutation object of the builder. +func (ilu *ImportListUpdate) Mutation() *ImportListMutation { + return ilu.mutation +} + +// Save executes the query and returns the number of nodes affected by the update operation. +func (ilu *ImportListUpdate) Save(ctx context.Context) (int, error) { + return withHooks(ctx, ilu.sqlSave, ilu.mutation, ilu.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (ilu *ImportListUpdate) SaveX(ctx context.Context) int { + affected, err := ilu.Save(ctx) + if err != nil { + panic(err) + } + return affected +} + +// Exec executes the query. +func (ilu *ImportListUpdate) Exec(ctx context.Context) error { + _, err := ilu.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (ilu *ImportListUpdate) ExecX(ctx context.Context) { + if err := ilu.Exec(ctx); err != nil { + panic(err) + } +} + +// check runs all checks and user-defined validators on the builder. +func (ilu *ImportListUpdate) check() error { + if v, ok := ilu.mutation.GetType(); ok { + if err := importlist.TypeValidator(v); err != nil { + return &ValidationError{Name: "type", err: fmt.Errorf(`ent: validator failed for field "ImportList.type": %w`, err)} + } + } + return nil +} + +func (ilu *ImportListUpdate) sqlSave(ctx context.Context) (n int, err error) { + if err := ilu.check(); err != nil { + return n, err + } + _spec := sqlgraph.NewUpdateSpec(importlist.Table, importlist.Columns, sqlgraph.NewFieldSpec(importlist.FieldID, field.TypeInt)) + if ps := ilu.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := ilu.mutation.Name(); ok { + _spec.SetField(importlist.FieldName, field.TypeString, value) + } + if value, ok := ilu.mutation.GetType(); ok { + _spec.SetField(importlist.FieldType, field.TypeEnum, value) + } + if value, ok := ilu.mutation.URL(); ok { + _spec.SetField(importlist.FieldURL, field.TypeString, value) + } + if ilu.mutation.URLCleared() { + _spec.ClearField(importlist.FieldURL, field.TypeString) + } + if value, ok := ilu.mutation.Qulity(); ok { + _spec.SetField(importlist.FieldQulity, field.TypeString, value) + } + if value, ok := ilu.mutation.StorageID(); ok { + _spec.SetField(importlist.FieldStorageID, field.TypeInt, value) + } + if value, ok := ilu.mutation.AddedStorageID(); ok { + _spec.AddField(importlist.FieldStorageID, field.TypeInt, value) + } + if value, ok := ilu.mutation.Settings(); ok { + _spec.SetField(importlist.FieldSettings, field.TypeJSON, value) + } + if ilu.mutation.SettingsCleared() { + _spec.ClearField(importlist.FieldSettings, field.TypeJSON) + } + if n, err = sqlgraph.UpdateNodes(ctx, ilu.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{importlist.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return 0, err + } + ilu.mutation.done = true + return n, nil +} + +// ImportListUpdateOne is the builder for updating a single ImportList entity. +type ImportListUpdateOne struct { + config + fields []string + hooks []Hook + mutation *ImportListMutation +} + +// SetName sets the "name" field. +func (iluo *ImportListUpdateOne) SetName(s string) *ImportListUpdateOne { + iluo.mutation.SetName(s) + return iluo +} + +// SetNillableName sets the "name" field if the given value is not nil. +func (iluo *ImportListUpdateOne) SetNillableName(s *string) *ImportListUpdateOne { + if s != nil { + iluo.SetName(*s) + } + return iluo +} + +// SetType sets the "type" field. +func (iluo *ImportListUpdateOne) SetType(i importlist.Type) *ImportListUpdateOne { + iluo.mutation.SetType(i) + return iluo +} + +// SetNillableType sets the "type" field if the given value is not nil. +func (iluo *ImportListUpdateOne) SetNillableType(i *importlist.Type) *ImportListUpdateOne { + if i != nil { + iluo.SetType(*i) + } + return iluo +} + +// SetURL sets the "url" field. +func (iluo *ImportListUpdateOne) SetURL(s string) *ImportListUpdateOne { + iluo.mutation.SetURL(s) + return iluo +} + +// SetNillableURL sets the "url" field if the given value is not nil. +func (iluo *ImportListUpdateOne) SetNillableURL(s *string) *ImportListUpdateOne { + if s != nil { + iluo.SetURL(*s) + } + return iluo +} + +// ClearURL clears the value of the "url" field. +func (iluo *ImportListUpdateOne) ClearURL() *ImportListUpdateOne { + iluo.mutation.ClearURL() + return iluo +} + +// SetQulity sets the "qulity" field. +func (iluo *ImportListUpdateOne) SetQulity(s string) *ImportListUpdateOne { + iluo.mutation.SetQulity(s) + return iluo +} + +// SetNillableQulity sets the "qulity" field if the given value is not nil. +func (iluo *ImportListUpdateOne) SetNillableQulity(s *string) *ImportListUpdateOne { + if s != nil { + iluo.SetQulity(*s) + } + return iluo +} + +// SetStorageID sets the "storage_id" field. +func (iluo *ImportListUpdateOne) SetStorageID(i int) *ImportListUpdateOne { + iluo.mutation.ResetStorageID() + iluo.mutation.SetStorageID(i) + return iluo +} + +// SetNillableStorageID sets the "storage_id" field if the given value is not nil. +func (iluo *ImportListUpdateOne) SetNillableStorageID(i *int) *ImportListUpdateOne { + if i != nil { + iluo.SetStorageID(*i) + } + return iluo +} + +// AddStorageID adds i to the "storage_id" field. +func (iluo *ImportListUpdateOne) AddStorageID(i int) *ImportListUpdateOne { + iluo.mutation.AddStorageID(i) + return iluo +} + +// SetSettings sets the "settings" field. +func (iluo *ImportListUpdateOne) SetSettings(sls schema.ImportListSettings) *ImportListUpdateOne { + iluo.mutation.SetSettings(sls) + return iluo +} + +// SetNillableSettings sets the "settings" field if the given value is not nil. +func (iluo *ImportListUpdateOne) SetNillableSettings(sls *schema.ImportListSettings) *ImportListUpdateOne { + if sls != nil { + iluo.SetSettings(*sls) + } + return iluo +} + +// ClearSettings clears the value of the "settings" field. +func (iluo *ImportListUpdateOne) ClearSettings() *ImportListUpdateOne { + iluo.mutation.ClearSettings() + return iluo +} + +// Mutation returns the ImportListMutation object of the builder. +func (iluo *ImportListUpdateOne) Mutation() *ImportListMutation { + return iluo.mutation +} + +// Where appends a list predicates to the ImportListUpdate builder. +func (iluo *ImportListUpdateOne) Where(ps ...predicate.ImportList) *ImportListUpdateOne { + iluo.mutation.Where(ps...) + return iluo +} + +// Select allows selecting one or more fields (columns) of the returned entity. +// The default is selecting all fields defined in the entity schema. +func (iluo *ImportListUpdateOne) Select(field string, fields ...string) *ImportListUpdateOne { + iluo.fields = append([]string{field}, fields...) + return iluo +} + +// Save executes the query and returns the updated ImportList entity. +func (iluo *ImportListUpdateOne) Save(ctx context.Context) (*ImportList, error) { + return withHooks(ctx, iluo.sqlSave, iluo.mutation, iluo.hooks) +} + +// SaveX is like Save, but panics if an error occurs. +func (iluo *ImportListUpdateOne) SaveX(ctx context.Context) *ImportList { + node, err := iluo.Save(ctx) + if err != nil { + panic(err) + } + return node +} + +// Exec executes the query on the entity. +func (iluo *ImportListUpdateOne) Exec(ctx context.Context) error { + _, err := iluo.Save(ctx) + return err +} + +// ExecX is like Exec, but panics if an error occurs. +func (iluo *ImportListUpdateOne) ExecX(ctx context.Context) { + if err := iluo.Exec(ctx); err != nil { + panic(err) + } +} + +// check runs all checks and user-defined validators on the builder. +func (iluo *ImportListUpdateOne) check() error { + if v, ok := iluo.mutation.GetType(); ok { + if err := importlist.TypeValidator(v); err != nil { + return &ValidationError{Name: "type", err: fmt.Errorf(`ent: validator failed for field "ImportList.type": %w`, err)} + } + } + return nil +} + +func (iluo *ImportListUpdateOne) sqlSave(ctx context.Context) (_node *ImportList, err error) { + if err := iluo.check(); err != nil { + return _node, err + } + _spec := sqlgraph.NewUpdateSpec(importlist.Table, importlist.Columns, sqlgraph.NewFieldSpec(importlist.FieldID, field.TypeInt)) + id, ok := iluo.mutation.ID() + if !ok { + return nil, &ValidationError{Name: "id", err: errors.New(`ent: missing "ImportList.id" for update`)} + } + _spec.Node.ID.Value = id + if fields := iluo.fields; len(fields) > 0 { + _spec.Node.Columns = make([]string, 0, len(fields)) + _spec.Node.Columns = append(_spec.Node.Columns, importlist.FieldID) + for _, f := range fields { + if !importlist.ValidColumn(f) { + return nil, &ValidationError{Name: f, err: fmt.Errorf("ent: invalid field %q for query", f)} + } + if f != importlist.FieldID { + _spec.Node.Columns = append(_spec.Node.Columns, f) + } + } + } + if ps := iluo.mutation.predicates; len(ps) > 0 { + _spec.Predicate = func(selector *sql.Selector) { + for i := range ps { + ps[i](selector) + } + } + } + if value, ok := iluo.mutation.Name(); ok { + _spec.SetField(importlist.FieldName, field.TypeString, value) + } + if value, ok := iluo.mutation.GetType(); ok { + _spec.SetField(importlist.FieldType, field.TypeEnum, value) + } + if value, ok := iluo.mutation.URL(); ok { + _spec.SetField(importlist.FieldURL, field.TypeString, value) + } + if iluo.mutation.URLCleared() { + _spec.ClearField(importlist.FieldURL, field.TypeString) + } + if value, ok := iluo.mutation.Qulity(); ok { + _spec.SetField(importlist.FieldQulity, field.TypeString, value) + } + if value, ok := iluo.mutation.StorageID(); ok { + _spec.SetField(importlist.FieldStorageID, field.TypeInt, value) + } + if value, ok := iluo.mutation.AddedStorageID(); ok { + _spec.AddField(importlist.FieldStorageID, field.TypeInt, value) + } + if value, ok := iluo.mutation.Settings(); ok { + _spec.SetField(importlist.FieldSettings, field.TypeJSON, value) + } + if iluo.mutation.SettingsCleared() { + _spec.ClearField(importlist.FieldSettings, field.TypeJSON) + } + _node = &ImportList{config: iluo.config} + _spec.Assign = _node.assignValues + _spec.ScanValues = _node.scanValues + if err = sqlgraph.UpdateNode(ctx, iluo.driver, _spec); err != nil { + if _, ok := err.(*sqlgraph.NotFoundError); ok { + err = &NotFoundError{importlist.Label} + } else if sqlgraph.IsConstraintError(err) { + err = &ConstraintError{msg: err.Error(), wrap: err} + } + return nil, err + } + iluo.mutation.done = true + return _node, nil +} diff --git a/ent/migrate/schema.go b/ent/migrate/schema.go index 04be080..ce39f45 100644 --- a/ent/migrate/schema.go +++ b/ent/migrate/schema.go @@ -76,6 +76,22 @@ var ( Columns: HistoriesColumns, PrimaryKey: []*schema.Column{HistoriesColumns[0]}, } + // ImportListsColumns holds the columns for the "import_lists" table. + ImportListsColumns = []*schema.Column{ + {Name: "id", Type: field.TypeInt, Increment: true}, + {Name: "name", Type: field.TypeString}, + {Name: "type", Type: field.TypeEnum, Enums: []string{"plex", "doulist"}}, + {Name: "url", Type: field.TypeString, Nullable: true}, + {Name: "qulity", Type: field.TypeString}, + {Name: "storage_id", Type: field.TypeInt}, + {Name: "settings", Type: field.TypeJSON, Nullable: true}, + } + // ImportListsTable holds the schema information for the "import_lists" table. + ImportListsTable = &schema.Table{ + Name: "import_lists", + Columns: ImportListsColumns, + PrimaryKey: []*schema.Column{ImportListsColumns[0]}, + } // IndexersColumns holds the columns for the "indexers" table. IndexersColumns = []*schema.Column{ {Name: "id", Type: field.TypeInt, Increment: true}, @@ -166,6 +182,7 @@ var ( DownloadClientsTable, EpisodesTable, HistoriesTable, + ImportListsTable, IndexersTable, MediaTable, NotificationClientsTable, diff --git a/ent/mutation.go b/ent/mutation.go index bcc9fb8..a5acfe3 100644 --- a/ent/mutation.go +++ b/ent/mutation.go @@ -9,6 +9,7 @@ import ( "polaris/ent/downloadclients" "polaris/ent/episode" "polaris/ent/history" + "polaris/ent/importlist" "polaris/ent/indexers" "polaris/ent/media" "polaris/ent/notificationclient" @@ -35,6 +36,7 @@ const ( TypeDownloadClients = "DownloadClients" TypeEpisode = "Episode" TypeHistory = "History" + TypeImportList = "ImportList" TypeIndexers = "Indexers" TypeMedia = "Media" TypeNotificationClient = "NotificationClient" @@ -2892,6 +2894,679 @@ func (m *HistoryMutation) ResetEdge(name string) error { return fmt.Errorf("unknown History edge %s", name) } +// ImportListMutation represents an operation that mutates the ImportList nodes in the graph. +type ImportListMutation struct { + config + op Op + typ string + id *int + name *string + _type *importlist.Type + url *string + qulity *string + storage_id *int + addstorage_id *int + settings *schema.ImportListSettings + clearedFields map[string]struct{} + done bool + oldValue func(context.Context) (*ImportList, error) + predicates []predicate.ImportList +} + +var _ ent.Mutation = (*ImportListMutation)(nil) + +// importlistOption allows management of the mutation configuration using functional options. +type importlistOption func(*ImportListMutation) + +// newImportListMutation creates new mutation for the ImportList entity. +func newImportListMutation(c config, op Op, opts ...importlistOption) *ImportListMutation { + m := &ImportListMutation{ + config: c, + op: op, + typ: TypeImportList, + clearedFields: make(map[string]struct{}), + } + for _, opt := range opts { + opt(m) + } + return m +} + +// withImportListID sets the ID field of the mutation. +func withImportListID(id int) importlistOption { + return func(m *ImportListMutation) { + var ( + err error + once sync.Once + value *ImportList + ) + m.oldValue = func(ctx context.Context) (*ImportList, error) { + once.Do(func() { + if m.done { + err = errors.New("querying old values post mutation is not allowed") + } else { + value, err = m.Client().ImportList.Get(ctx, id) + } + }) + return value, err + } + m.id = &id + } +} + +// withImportList sets the old ImportList of the mutation. +func withImportList(node *ImportList) importlistOption { + return func(m *ImportListMutation) { + m.oldValue = func(context.Context) (*ImportList, error) { + return node, nil + } + m.id = &node.ID + } +} + +// Client returns a new `ent.Client` from the mutation. If the mutation was +// executed in a transaction (ent.Tx), a transactional client is returned. +func (m ImportListMutation) Client() *Client { + client := &Client{config: m.config} + client.init() + return client +} + +// Tx returns an `ent.Tx` for mutations that were executed in transactions; +// it returns an error otherwise. +func (m ImportListMutation) Tx() (*Tx, error) { + if _, ok := m.driver.(*txDriver); !ok { + return nil, errors.New("ent: mutation is not running in a transaction") + } + tx := &Tx{config: m.config} + tx.init() + return tx, nil +} + +// ID returns the ID value in the mutation. Note that the ID is only available +// if it was provided to the builder or after it was returned from the database. +func (m *ImportListMutation) ID() (id int, exists bool) { + if m.id == nil { + return + } + return *m.id, true +} + +// IDs queries the database and returns the entity ids that match the mutation's predicate. +// That means, if the mutation is applied within a transaction with an isolation level such +// as sql.LevelSerializable, the returned ids match the ids of the rows that will be updated +// or updated by the mutation. +func (m *ImportListMutation) IDs(ctx context.Context) ([]int, error) { + switch { + case m.op.Is(OpUpdateOne | OpDeleteOne): + id, exists := m.ID() + if exists { + return []int{id}, nil + } + fallthrough + case m.op.Is(OpUpdate | OpDelete): + return m.Client().ImportList.Query().Where(m.predicates...).IDs(ctx) + default: + return nil, fmt.Errorf("IDs is not allowed on %s operations", m.op) + } +} + +// SetName sets the "name" field. +func (m *ImportListMutation) SetName(s string) { + m.name = &s +} + +// Name returns the value of the "name" field in the mutation. +func (m *ImportListMutation) Name() (r string, exists bool) { + v := m.name + if v == nil { + return + } + return *v, true +} + +// OldName returns the old "name" field's value of the ImportList entity. +// If the ImportList 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 *ImportListMutation) OldName(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldName is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldName requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldName: %w", err) + } + return oldValue.Name, nil +} + +// ResetName resets all changes to the "name" field. +func (m *ImportListMutation) ResetName() { + m.name = nil +} + +// SetType sets the "type" field. +func (m *ImportListMutation) SetType(i importlist.Type) { + m._type = &i +} + +// GetType returns the value of the "type" field in the mutation. +func (m *ImportListMutation) GetType() (r importlist.Type, exists bool) { + v := m._type + if v == nil { + return + } + return *v, true +} + +// OldType returns the old "type" field's value of the ImportList entity. +// If the ImportList 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 *ImportListMutation) OldType(ctx context.Context) (v importlist.Type, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldType is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldType requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldType: %w", err) + } + return oldValue.Type, nil +} + +// ResetType resets all changes to the "type" field. +func (m *ImportListMutation) ResetType() { + m._type = nil +} + +// SetURL sets the "url" field. +func (m *ImportListMutation) SetURL(s string) { + m.url = &s +} + +// URL returns the value of the "url" field in the mutation. +func (m *ImportListMutation) URL() (r string, exists bool) { + v := m.url + if v == nil { + return + } + return *v, true +} + +// OldURL returns the old "url" field's value of the ImportList entity. +// If the ImportList 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 *ImportListMutation) OldURL(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldURL is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldURL requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldURL: %w", err) + } + return oldValue.URL, nil +} + +// ClearURL clears the value of the "url" field. +func (m *ImportListMutation) ClearURL() { + m.url = nil + m.clearedFields[importlist.FieldURL] = struct{}{} +} + +// URLCleared returns if the "url" field was cleared in this mutation. +func (m *ImportListMutation) URLCleared() bool { + _, ok := m.clearedFields[importlist.FieldURL] + return ok +} + +// ResetURL resets all changes to the "url" field. +func (m *ImportListMutation) ResetURL() { + m.url = nil + delete(m.clearedFields, importlist.FieldURL) +} + +// SetQulity sets the "qulity" field. +func (m *ImportListMutation) SetQulity(s string) { + m.qulity = &s +} + +// Qulity returns the value of the "qulity" field in the mutation. +func (m *ImportListMutation) Qulity() (r string, exists bool) { + v := m.qulity + if v == nil { + return + } + return *v, true +} + +// OldQulity returns the old "qulity" field's value of the ImportList entity. +// If the ImportList 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 *ImportListMutation) OldQulity(ctx context.Context) (v string, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldQulity is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldQulity requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldQulity: %w", err) + } + return oldValue.Qulity, nil +} + +// ResetQulity resets all changes to the "qulity" field. +func (m *ImportListMutation) ResetQulity() { + m.qulity = nil +} + +// SetStorageID sets the "storage_id" field. +func (m *ImportListMutation) SetStorageID(i int) { + m.storage_id = &i + m.addstorage_id = nil +} + +// StorageID returns the value of the "storage_id" field in the mutation. +func (m *ImportListMutation) StorageID() (r int, exists bool) { + v := m.storage_id + if v == nil { + return + } + return *v, true +} + +// OldStorageID returns the old "storage_id" field's value of the ImportList entity. +// If the ImportList 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 *ImportListMutation) OldStorageID(ctx context.Context) (v int, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldStorageID is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldStorageID requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldStorageID: %w", err) + } + return oldValue.StorageID, nil +} + +// AddStorageID adds i to the "storage_id" field. +func (m *ImportListMutation) AddStorageID(i int) { + if m.addstorage_id != nil { + *m.addstorage_id += i + } else { + m.addstorage_id = &i + } +} + +// AddedStorageID returns the value that was added to the "storage_id" field in this mutation. +func (m *ImportListMutation) AddedStorageID() (r int, exists bool) { + v := m.addstorage_id + if v == nil { + return + } + return *v, true +} + +// ResetStorageID resets all changes to the "storage_id" field. +func (m *ImportListMutation) ResetStorageID() { + m.storage_id = nil + m.addstorage_id = nil +} + +// SetSettings sets the "settings" field. +func (m *ImportListMutation) SetSettings(sls schema.ImportListSettings) { + m.settings = &sls +} + +// Settings returns the value of the "settings" field in the mutation. +func (m *ImportListMutation) Settings() (r schema.ImportListSettings, exists bool) { + v := m.settings + if v == nil { + return + } + return *v, true +} + +// OldSettings returns the old "settings" field's value of the ImportList entity. +// If the ImportList 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 *ImportListMutation) OldSettings(ctx context.Context) (v schema.ImportListSettings, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldSettings is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldSettings requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldSettings: %w", err) + } + return oldValue.Settings, nil +} + +// ClearSettings clears the value of the "settings" field. +func (m *ImportListMutation) ClearSettings() { + m.settings = nil + m.clearedFields[importlist.FieldSettings] = struct{}{} +} + +// SettingsCleared returns if the "settings" field was cleared in this mutation. +func (m *ImportListMutation) SettingsCleared() bool { + _, ok := m.clearedFields[importlist.FieldSettings] + return ok +} + +// ResetSettings resets all changes to the "settings" field. +func (m *ImportListMutation) ResetSettings() { + m.settings = nil + delete(m.clearedFields, importlist.FieldSettings) +} + +// Where appends a list predicates to the ImportListMutation builder. +func (m *ImportListMutation) Where(ps ...predicate.ImportList) { + m.predicates = append(m.predicates, ps...) +} + +// WhereP appends storage-level predicates to the ImportListMutation builder. Using this method, +// users can use type-assertion to append predicates that do not depend on any generated package. +func (m *ImportListMutation) WhereP(ps ...func(*sql.Selector)) { + p := make([]predicate.ImportList, len(ps)) + for i := range ps { + p[i] = ps[i] + } + m.Where(p...) +} + +// Op returns the operation name. +func (m *ImportListMutation) Op() Op { + return m.op +} + +// SetOp allows setting the mutation operation. +func (m *ImportListMutation) SetOp(op Op) { + m.op = op +} + +// Type returns the node type of this mutation (ImportList). +func (m *ImportListMutation) Type() string { + return m.typ +} + +// Fields returns all fields that were changed during this mutation. Note that in +// order to get all numeric fields that were incremented/decremented, call +// AddedFields(). +func (m *ImportListMutation) Fields() []string { + fields := make([]string, 0, 6) + if m.name != nil { + fields = append(fields, importlist.FieldName) + } + if m._type != nil { + fields = append(fields, importlist.FieldType) + } + if m.url != nil { + fields = append(fields, importlist.FieldURL) + } + if m.qulity != nil { + fields = append(fields, importlist.FieldQulity) + } + if m.storage_id != nil { + fields = append(fields, importlist.FieldStorageID) + } + if m.settings != nil { + fields = append(fields, importlist.FieldSettings) + } + return fields +} + +// Field returns the value of a field with the given name. The second boolean +// return value indicates that this field was not set, or was not defined in the +// schema. +func (m *ImportListMutation) Field(name string) (ent.Value, bool) { + switch name { + case importlist.FieldName: + return m.Name() + case importlist.FieldType: + return m.GetType() + case importlist.FieldURL: + return m.URL() + case importlist.FieldQulity: + return m.Qulity() + case importlist.FieldStorageID: + return m.StorageID() + case importlist.FieldSettings: + return m.Settings() + } + return nil, false +} + +// OldField returns the old value of the field from the database. An error is +// returned if the mutation operation is not UpdateOne, or the query to the +// database failed. +func (m *ImportListMutation) OldField(ctx context.Context, name string) (ent.Value, error) { + switch name { + case importlist.FieldName: + return m.OldName(ctx) + case importlist.FieldType: + return m.OldType(ctx) + case importlist.FieldURL: + return m.OldURL(ctx) + case importlist.FieldQulity: + return m.OldQulity(ctx) + case importlist.FieldStorageID: + return m.OldStorageID(ctx) + case importlist.FieldSettings: + return m.OldSettings(ctx) + } + return nil, fmt.Errorf("unknown ImportList field %s", name) +} + +// SetField sets the value of a field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *ImportListMutation) SetField(name string, value ent.Value) error { + switch name { + case importlist.FieldName: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetName(v) + return nil + case importlist.FieldType: + v, ok := value.(importlist.Type) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetType(v) + return nil + case importlist.FieldURL: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetURL(v) + return nil + case importlist.FieldQulity: + v, ok := value.(string) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetQulity(v) + return nil + case importlist.FieldStorageID: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetStorageID(v) + return nil + case importlist.FieldSettings: + v, ok := value.(schema.ImportListSettings) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetSettings(v) + return nil + } + return fmt.Errorf("unknown ImportList field %s", name) +} + +// AddedFields returns all numeric fields that were incremented/decremented during +// this mutation. +func (m *ImportListMutation) AddedFields() []string { + var fields []string + if m.addstorage_id != nil { + fields = append(fields, importlist.FieldStorageID) + } + return fields +} + +// AddedField returns the numeric value that was incremented/decremented on a field +// with the given name. The second boolean return value indicates that this field +// was not set, or was not defined in the schema. +func (m *ImportListMutation) AddedField(name string) (ent.Value, bool) { + switch name { + case importlist.FieldStorageID: + return m.AddedStorageID() + } + return nil, false +} + +// AddField adds the value to the field with the given name. It returns an error if +// the field is not defined in the schema, or if the type mismatched the field +// type. +func (m *ImportListMutation) AddField(name string, value ent.Value) error { + switch name { + case importlist.FieldStorageID: + v, ok := value.(int) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.AddStorageID(v) + return nil + } + return fmt.Errorf("unknown ImportList numeric field %s", name) +} + +// ClearedFields returns all nullable fields that were cleared during this +// mutation. +func (m *ImportListMutation) ClearedFields() []string { + var fields []string + if m.FieldCleared(importlist.FieldURL) { + fields = append(fields, importlist.FieldURL) + } + if m.FieldCleared(importlist.FieldSettings) { + fields = append(fields, importlist.FieldSettings) + } + return fields +} + +// FieldCleared returns a boolean indicating if a field with the given name was +// cleared in this mutation. +func (m *ImportListMutation) FieldCleared(name string) bool { + _, ok := m.clearedFields[name] + return ok +} + +// ClearField clears the value of the field with the given name. It returns an +// error if the field is not defined in the schema. +func (m *ImportListMutation) ClearField(name string) error { + switch name { + case importlist.FieldURL: + m.ClearURL() + return nil + case importlist.FieldSettings: + m.ClearSettings() + return nil + } + return fmt.Errorf("unknown ImportList nullable field %s", name) +} + +// ResetField resets all changes in the mutation for the field with the given name. +// It returns an error if the field is not defined in the schema. +func (m *ImportListMutation) ResetField(name string) error { + switch name { + case importlist.FieldName: + m.ResetName() + return nil + case importlist.FieldType: + m.ResetType() + return nil + case importlist.FieldURL: + m.ResetURL() + return nil + case importlist.FieldQulity: + m.ResetQulity() + return nil + case importlist.FieldStorageID: + m.ResetStorageID() + return nil + case importlist.FieldSettings: + m.ResetSettings() + return nil + } + return fmt.Errorf("unknown ImportList field %s", name) +} + +// AddedEdges returns all edge names that were set/added in this mutation. +func (m *ImportListMutation) AddedEdges() []string { + edges := make([]string, 0, 0) + return edges +} + +// AddedIDs returns all IDs (to other nodes) that were added for the given edge +// name in this mutation. +func (m *ImportListMutation) AddedIDs(name string) []ent.Value { + return nil +} + +// RemovedEdges returns all edge names that were removed in this mutation. +func (m *ImportListMutation) RemovedEdges() []string { + edges := make([]string, 0, 0) + return edges +} + +// RemovedIDs returns all IDs (to other nodes) that were removed for the edge with +// the given name in this mutation. +func (m *ImportListMutation) RemovedIDs(name string) []ent.Value { + return nil +} + +// ClearedEdges returns all edge names that were cleared in this mutation. +func (m *ImportListMutation) ClearedEdges() []string { + edges := make([]string, 0, 0) + return edges +} + +// EdgeCleared returns a boolean which indicates if the edge with the given name +// was cleared in this mutation. +func (m *ImportListMutation) EdgeCleared(name string) bool { + return false +} + +// ClearEdge clears the value of the edge with the given name. It returns an error +// if that edge is not defined in the schema. +func (m *ImportListMutation) ClearEdge(name string) error { + return fmt.Errorf("unknown ImportList unique edge %s", name) +} + +// ResetEdge resets all changes to the edge with the given name in this mutation. +// It returns an error if the edge is not defined in the schema. +func (m *ImportListMutation) ResetEdge(name string) error { + return fmt.Errorf("unknown ImportList edge %s", name) +} + // IndexersMutation represents an operation that mutates the Indexers nodes in the graph. type IndexersMutation struct { config diff --git a/ent/predicate/predicate.go b/ent/predicate/predicate.go index 859847f..53f25fa 100644 --- a/ent/predicate/predicate.go +++ b/ent/predicate/predicate.go @@ -15,6 +15,9 @@ type Episode func(*sql.Selector) // History is the predicate function for history builders. type History func(*sql.Selector) +// ImportList is the predicate function for importlist builders. +type ImportList func(*sql.Selector) + // Indexers is the predicate function for indexers builders. type Indexers func(*sql.Selector) diff --git a/ent/schema/importlist.go b/ent/schema/importlist.go new file mode 100644 index 0000000..816b7b5 --- /dev/null +++ b/ent/schema/importlist.go @@ -0,0 +1,32 @@ +package schema + +import ( + "entgo.io/ent" + "entgo.io/ent/schema/field" +) + +// ImportList holds the schema definition for the ImportList entity. +type ImportList struct { + ent.Schema +} + +// Fields of the ImportList. +func (ImportList) Fields() []ent.Field { + return []ent.Field{ + field.String("name"), + field.Enum("type").Values("plex", "doulist"), + field.String("url").Optional(), + field.String("qulity"), + field.Int("storage_id"), + field.JSON("settings", ImportListSettings{}).Optional(), + } +} + +// Edges of the ImportList. +func (ImportList) Edges() []ent.Edge { + return nil +} + +type ImportListSettings struct { + //Url string `json:"url"` +} \ No newline at end of file diff --git a/ent/tx.go b/ent/tx.go index bf1d3be..17aee3b 100644 --- a/ent/tx.go +++ b/ent/tx.go @@ -18,6 +18,8 @@ type Tx struct { Episode *EpisodeClient // History is the client for interacting with the History builders. History *HistoryClient + // ImportList is the client for interacting with the ImportList builders. + ImportList *ImportListClient // Indexers is the client for interacting with the Indexers builders. Indexers *IndexersClient // Media is the client for interacting with the Media builders. @@ -162,6 +164,7 @@ func (tx *Tx) init() { tx.DownloadClients = NewDownloadClientsClient(tx.config) tx.Episode = NewEpisodeClient(tx.config) tx.History = NewHistoryClient(tx.config) + tx.ImportList = NewImportListClient(tx.config) tx.Indexers = NewIndexersClient(tx.config) tx.Media = NewMediaClient(tx.config) tx.NotificationClient = NewNotificationClientClient(tx.config) diff --git a/go.mod b/go.mod index 55a69df..4797464 100644 --- a/go.mod +++ b/go.mod @@ -19,6 +19,8 @@ require ( require ( github.com/BurntSushi/toml v1.4.0 // indirect + github.com/PuerkitoBio/goquery v1.9.2 // indirect + github.com/andybalholm/cascadia v1.3.2 // indirect github.com/blinkbean/dingtalk v1.1.3 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible // indirect diff --git a/go.sum b/go.sum index 9c46dbe..f587ef8 100644 --- a/go.sum +++ b/go.sum @@ -6,8 +6,12 @@ github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0 github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/PuerkitoBio/goquery v1.9.2 h1:4/wZksC3KgkQw7SQgkKotmKljk0M6V8TUvA8Wb4yPeE= +github.com/PuerkitoBio/goquery v1.9.2/go.mod h1:GHPCaP0ODyyxqcNoFGYlAprUFH81NuRPd0GX3Zu2Mvk= github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tjT8= github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= +github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss= +github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU= github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= github.com/blinkbean/dingtalk v1.1.3 h1:MbidFZYom7DTFHD/YIs+eaI7kRy52kmWE/sy0xjo6E4= @@ -172,6 +176,7 @@ github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65E github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= github.com/zclconf/go-cty v1.8.0 h1:s4AvqaeQzJIu3ndv4gVIhplVD0krU+bgrcLSVUnaWuA= github.com/zclconf/go-cty v1.8.0/go.mod h1:vVKLxnk3puL4qRAv72AO+W99LUD4da90g3uUAzyuvAk= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= @@ -184,31 +189,59 @@ golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUu golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +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.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= diff --git a/pkg/importlist/douban/douban.go b/pkg/importlist/douban/douban.go new file mode 100644 index 0000000..dca1456 --- /dev/null +++ b/pkg/importlist/douban/douban.go @@ -0,0 +1,31 @@ +package douban + +import ( + "fmt" + "net/http" + + "github.com/PuerkitoBio/goquery" +) + +type DoulistItem struct { + Name string + ImdbID string +} + +func ParseDoulist(doulistUrl string) ([]DoulistItem, error) { + res, err := http.Get(doulistUrl) + if err != nil { + return nil, err + } + defer res.Body.Close() + if res.StatusCode != 200 { + return nil, fmt.Errorf("status code error: %d %s", res.StatusCode, res.Status) + + } + doc, err := goquery.NewDocumentFromReader(res.Body) + if err != nil { + return nil, err + } + doc.Find("") + return nil, nil +} diff --git a/pkg/importlist/importlist.go b/pkg/importlist/importlist.go new file mode 100644 index 0000000..3591c68 --- /dev/null +++ b/pkg/importlist/importlist.go @@ -0,0 +1,12 @@ +package importlist + +type Item struct { + Title string + ImdbID string + TvdbID string + TmdbID string +} + +type Response struct { + Items []Item +} diff --git a/pkg/importlist/plexwatchlist/plex.go b/pkg/importlist/plexwatchlist/plex.go new file mode 100644 index 0000000..7925f60 --- /dev/null +++ b/pkg/importlist/plexwatchlist/plex.go @@ -0,0 +1,96 @@ +package plexwatchlist + +import ( + "encoding/xml" + "io" + "net/http" + "polaris/pkg/importlist" + "strings" + + "github.com/pkg/errors" +) + +type Response struct { + XMLName xml.Name `xml:"rss"` + Text string `xml:",chardata"` + Atom string `xml:"atom,attr"` + Media string `xml:"media,attr"` + Version string `xml:"version,attr"` + Channel struct { + Text string `xml:",chardata"` + Title string `xml:"title"` + Link struct { + Text string `xml:",chardata"` + Href string `xml:"href,attr"` + Rel string `xml:"rel,attr"` + Type string `xml:"type,attr"` + } `xml:"link"` + Description string `xml:"description"` + Category string `xml:"category"` + Item []struct { + Text string `xml:",chardata"` + Title string `xml:"title"` + PubDate string `xml:"pubDate"` + Link string `xml:"link"` + Description string `xml:"description"` + Category string `xml:"category"` + Credit []struct { + Text string `xml:",chardata"` + Role string `xml:"role,attr"` + } `xml:"credit"` + Thumbnail struct { + Text string `xml:",chardata"` + URL string `xml:"url,attr"` + } `xml:"thumbnail"` + Keywords string `xml:"keywords"` + Rating struct { + Text string `xml:",chardata"` + Scheme string `xml:"scheme,attr"` + } `xml:"rating"` + Guid struct { + Text string `xml:",chardata"` + IsPermaLink string `xml:"isPermaLink,attr"` + } `xml:"guid"` + } `xml:"item"` + } `xml:"channel"` +} + +func (r *Response) convert() *importlist.Response { + res := &importlist.Response{} + for _, im := range r.Channel.Item { + item := importlist.Item{ + Title: im.Title, + } + id := strings.ToLower(im.Guid.Text) + if strings.HasPrefix(id, "tvdb") { + tvdbid := strings.TrimPrefix(id, "tvdb://") + item.TvdbID = tvdbid + } else if strings.HasPrefix(id, "imdb") { + imdbid := strings.TrimPrefix(id, "imdb://") + item.ImdbID = imdbid + } else if strings.HasPrefix(id, "tmdb") { + tmdbid := strings.TrimPrefix(id, "tmdb://") + item.TmdbID = tmdbid + } + res.Items = append(res.Items, item) + } + return res +} + +func ParsePlexWatchlist(url string) (*importlist.Response, error) { + resp, err := http.Get(url) + if err != nil { + return nil, errors.Wrap(err, "http get") + } + defer resp.Body.Close() + data, err := io.ReadAll(resp.Body) + if err != nil { + return nil, errors.Wrap(err, "read data") + } + var rrr Response + err = xml.Unmarshal(data, &rrr) + if err != nil { + return nil, errors.Wrap(err, "xml") + } + return rrr.convert(), nil +} diff --git a/pkg/tmdb/tmdb.go b/pkg/tmdb/tmdb.go index 0cfd26e..78bca01 100644 --- a/pkg/tmdb/tmdb.go +++ b/pkg/tmdb/tmdb.go @@ -213,6 +213,19 @@ func (c *Client) GetMovieAlternativeTitles(id int, language string) (*tmdb.Movie return c.tmdbClient.GetMovieAlternativeTitles(id, withLangOption(language)) } +func (c *Client) GetByImdbId(imdbId string, lang string)(*tmdb.FindByID, error) { + m := withLangOption(lang) + m["external_source"] = "imdb_id" + return c.tmdbClient.GetFindByID(imdbId, m) +} + +func (c *Client) GetByTvdbId(imdbId string, lang string)(*tmdb.FindByID, error) { + m := withLangOption(lang) + m["external_source"] = "tvdb_id" + return c.tmdbClient.GetFindByID(imdbId, m) +} + + func wrapLanguage(lang string) string { if lang == "" { diff --git a/server/core/importlist.go b/server/core/importlist.go new file mode 100644 index 0000000..606509b --- /dev/null +++ b/server/core/importlist.go @@ -0,0 +1,400 @@ +package core + +import ( + "fmt" + "io" + "net/http" + "os" + "path/filepath" + "polaris/db" + "polaris/ent" + "polaris/ent/importlist" + "polaris/ent/media" + "polaris/ent/schema" + "polaris/log" + "polaris/pkg/importlist/plexwatchlist" + "regexp" + "strings" + "time" + + tmdb "github.com/cyruzin/golang-tmdb" + "github.com/pkg/errors" +) + +func (c *Client) periodicallyUpdateImportlist() error { + lists, err := c.db.GetAllImportLists() + if err != nil { + return errors.Wrap(err, "get from db") + } + for _, l := range lists { + if l.Type == importlist.TypePlex { + res, err := plexwatchlist.ParsePlexWatchlist(l.URL) + if err != nil { + log.Errorf("parse plex watchlist: %v", err) + continue + } + for _, item := range res.Items { + var tmdbRes *tmdb.FindByID + if item.ImdbID != "" { + tmdbRes1, err := c.MustTMDB().GetByImdbId(item.ImdbID, c.language) + if err != nil { + log.Errorf("get by imdb id error: %v", err) + continue + } + tmdbRes = tmdbRes1 + } else if item.TvdbID != "" { + tmdbRes1, err := c.MustTMDB().GetByTvdbId(item.TvdbID, c.language) + if err != nil { + log.Errorf("get by imdb id error: %v", err) + continue + } + tmdbRes = tmdbRes1 + } + if tmdbRes == nil { + log.Errorf("can not find media for : %+v", item) + continue + } + if len(tmdbRes.MovieResults) > 0 { + d := tmdbRes.MovieResults[0] + name, err := c.SuggestedMovieFolderName(int(d.ID)) + if err != nil { + log.Errorf("suggesting name error: %v", err) + continue + } + c.AddMovie2Watchlist(AddWatchlistIn{ + TmdbID: int(d.ID), + StorageID: l.StorageID, + Resolution: l.Qulity, + Folder: name, + }) + } else if len(tmdbRes.TvResults) > 0 { + d := tmdbRes.TvResults[0] + name, err := c.SuggestedSeriesFolderName(int(d.ID)) + if err != nil { + log.Errorf("suggesting name error: %v", err) + continue + } + + c.AddTv2Watchlist(AddWatchlistIn{ + TmdbID: int(d.ID), + StorageID: l.StorageID, + Resolution: l.Qulity, + Folder: name, + }) + } + + } + } + } + return nil +} + +type AddWatchlistIn struct { + TmdbID int `json:"tmdb_id" binding:"required"` + StorageID int `json:"storage_id" ` + Resolution string `json:"resolution" binding:"required"` + Folder string `json:"folder" binding:"required"` + DownloadHistoryEpisodes bool `json:"download_history_episodes"` //for tv + SizeMin int `json:"size_min"` + SizeMax int `json:"size_max"` +} + +func (c *Client) AddTv2Watchlist(in AddWatchlistIn) (interface{}, error) { + log.Debugf("add tv watchlist input %+v", in) + if in.Folder == "" { + return nil, errors.New("folder should be provided") + } + detailCn, err := c.MustTMDB().GetTvDetails(in.TmdbID, db.LanguageCN) + if err != nil { + return nil, errors.Wrap(err, "get tv detail") + } + var nameCn = detailCn.Name + + detailEn, _ := c.MustTMDB().GetTvDetails(in.TmdbID, db.LanguageEN) + var nameEn = detailEn.Name + var detail *tmdb.TVDetails + if c.language == "" || c.language == db.LanguageCN { + detail = detailCn + } else { + detail = detailEn + } + log.Infof("find detail for tv id %d: %v", in.TmdbID, detail) + + var epIds []int + for _, season := range detail.Seasons { + seasonId := season.SeasonNumber + se, err := c.MustTMDB().GetSeasonDetails(int(detail.ID), seasonId, c.language) + if err != nil { + log.Errorf("get season detail (%s) error: %v", detail.Name, err) + continue + } + for _, ep := range se.Episodes { + shouldMonitor := false + //如果设置下载往期剧集,则监控所有剧集。如果没有则监控未上映的剧集,考虑时差等问题留24h余量 + if in.DownloadHistoryEpisodes { + shouldMonitor = true + } else { + t, err := time.Parse("2006-01-02", ep.AirDate) + if err != nil { + log.Error("air date not known, will monitor: %v", ep.AirDate) + shouldMonitor = true + + } else { + if time.Since(t) < 24*time.Hour { //monitor episode air 24h before now + shouldMonitor = true + } + } + } + + epid, err := c.db.SaveEposideDetail(&ent.Episode{ + SeasonNumber: seasonId, + EpisodeNumber: ep.EpisodeNumber, + Title: ep.Name, + Overview: ep.Overview, + AirDate: ep.AirDate, + Monitored: shouldMonitor, + }) + if err != nil { + log.Errorf("save episode info error: %v", err) + continue + } + epIds = append(epIds, epid) + } + } + m := &ent.Media{ + TmdbID: int(detail.ID), + ImdbID: detail.IMDbID, + MediaType: media.MediaTypeTv, + NameCn: nameCn, + NameEn: nameEn, + OriginalName: detail.OriginalName, + Overview: detail.Overview, + AirDate: detail.FirstAirDate, + Resolution: media.Resolution(in.Resolution), + StorageID: in.StorageID, + TargetDir: in.Folder, + DownloadHistoryEpisodes: in.DownloadHistoryEpisodes, + Limiter: schema.MediaLimiter{SizeMin: in.SizeMin, SizeMax: in.SizeMax}, + Extras: schema.MediaExtras{ + OriginalLanguage: detail.OriginalLanguage, + Genres: detail.Genres, + }, + } + + r, err := c.db.AddMediaWatchlist(m, epIds) + if err != nil { + return nil, errors.Wrap(err, "add to list") + } + go func() { + if err := c.downloadPoster(detail.PosterPath, r.ID); err != nil { + log.Errorf("download poster error: %v", err) + } + if err := c.downloadBackdrop(detail.BackdropPath, r.ID); err != nil { + log.Errorf("download poster error: %v", err) + } + if err := c.CheckDownloadedSeriesFiles(r); err != nil { + log.Errorf("check downloaded files error: %v", err) + } + + }() + + log.Infof("add tv %s to watchlist success", detail.Name) + return nil, nil +} + +func (c *Client) AddMovie2Watchlist(in AddWatchlistIn) (interface{}, error) { + log.Infof("add movie watchlist input: %+v", in) + detailCn, err := c.MustTMDB().GetMovieDetails(in.TmdbID, db.LanguageCN) + if err != nil { + return nil, errors.Wrap(err, "get movie detail") + } + var nameCn = detailCn.Title + + detailEn, _ := c.MustTMDB().GetMovieDetails(in.TmdbID, db.LanguageEN) + var nameEn = detailEn.Title + var detail *tmdb.MovieDetails + if c.language == "" || c.language == db.LanguageCN { + detail = detailCn + } else { + detail = detailEn + } + log.Infof("find detail for movie id %d: %v", in.TmdbID, detail) + + epid, err := c.db.SaveEposideDetail(&ent.Episode{ + SeasonNumber: 1, + EpisodeNumber: 1, + Title: "dummy episode for movies", + Overview: "dummy episode for movies", + AirDate: detail.ReleaseDate, + Monitored: true, + }) + if err != nil { + return nil, errors.Wrap(err, "add dummy episode") + } + log.Infof("added dummy episode for movie: %v", nameEn) + + movie := ent.Media{ + TmdbID: int(detail.ID), + ImdbID: detail.IMDbID, + MediaType: media.MediaTypeMovie, + NameCn: nameCn, + NameEn: nameEn, + OriginalName: detail.OriginalTitle, + Overview: detail.Overview, + AirDate: detail.ReleaseDate, + Resolution: media.Resolution(in.Resolution), + StorageID: in.StorageID, + TargetDir: in.Folder, + Limiter: schema.MediaLimiter{SizeMin: in.SizeMin, SizeMax: in.SizeMax}, + } + + extras := schema.MediaExtras{ + IsAdultMovie: detail.Adult, + OriginalLanguage: detail.OriginalLanguage, + Genres: detail.Genres, + } + if IsJav(detail) { + javid := c.GetJavid(in.TmdbID) + extras.JavId = javid + } + + movie.Extras = extras + r, err := c.db.AddMediaWatchlist(&movie, []int{epid}) + if err != nil { + return nil, errors.Wrap(err, "add to list") + } + go func() { + if err := c.downloadPoster(detail.PosterPath, r.ID); err != nil { + log.Errorf("download poster error: %v", err) + } + if err := c.downloadBackdrop(detail.BackdropPath, r.ID); err != nil { + log.Errorf("download backdrop error: %v", err) + } + }() + + log.Infof("add movie %s to watchlist success", detail.Title) + return nil, nil + +} + +func IsJav(detail *tmdb.MovieDetails) bool { + if detail.Adult && len(detail.ProductionCountries) > 0 && strings.ToUpper(detail.ProductionCountries[0].Iso3166_1) == "JP" { + return true + } + return false +} + +func (c *Client) GetJavid(id int) string { + alters, err := c.MustTMDB().GetMovieAlternativeTitles(id, c.language) + if err != nil { + return "" + } + for _, t := range alters.Titles { + if t.Iso3166_1 == "JP" && t.Type == "" { + return t.Title + } + } + return "" +} + +func (c *Client) downloadBackdrop(path string, mediaID int) error { + url := "https://image.tmdb.org/t/p/original" + path + return c.downloadImage(url, mediaID, "backdrop.jpg") +} + +func (c *Client) downloadPoster(path string, mediaID int) error { + var url = "https://image.tmdb.org/t/p/original" + path + + return c.downloadImage(url, mediaID, "poster.jpg") +} + +func (c *Client) downloadImage(url string, mediaID int, name string) error { + + log.Infof("try to download image: %v", url) + var resp, err = http.Get(url) + if err != nil { + return errors.Wrap(err, "http get") + } + targetDir := fmt.Sprintf("%v/%d", db.ImgPath, mediaID) + os.MkdirAll(targetDir, 0777) + //ext := filepath.Ext(path) + targetFile := filepath.Join(targetDir, name) + f, err := os.Create(targetFile) + if err != nil { + return errors.Wrap(err, "new file") + } + defer f.Close() + _, err = io.Copy(f, resp.Body) + if err != nil { + return errors.Wrap(err, "copy http response") + } + log.Infof("image successfully downlaoded: %v", targetFile) + return nil + +} + +func (c *Client) SuggestedMovieFolderName(tmdbId int) (string, error) { + + d1, err := c.MustTMDB().GetMovieDetails(tmdbId, c.language) + if err != nil { + return "", errors.Wrap(err, "get movie details") + } + name := d1.Title + + if IsJav(d1) { + javid := c.GetJavid(tmdbId) + if javid != "" { + return javid, nil + } + } + + if c.language == db.LanguageCN { + en, err := c.MustTMDB().GetMovieDetails(tmdbId, db.LanguageEN) + if err != nil { + log.Errorf("get en movie detail error: %v", err) + } else { + name = fmt.Sprintf("%s %s", d1.Title, en.Title) + } + } + //remove extra characters + re := regexp.MustCompile(`[^\p{L}\w\s]`) + name = re.ReplaceAllString(strings.ToLower(name), " ") + name = strings.Join(strings.Fields(name), " ") + year := strings.Split(d1.ReleaseDate, "-")[0] + if year != "" { + name = fmt.Sprintf("%s (%s)", name, year) + } + + log.Infof("tv series of tmdb id %v suggestting name is %v", tmdbId, name) + return name, nil +} + +func (c *Client) SuggestedSeriesFolderName(tmdbId int) (string, error) { + + d, err := c.MustTMDB().GetTvDetails(tmdbId, c.language) + if err != nil { + return "", errors.Wrap(err, "get tv details") + } + + name := d.Name + + if c.language == db.LanguageCN { + en, err := c.MustTMDB().GetTvDetails(tmdbId, db.LanguageEN) + if err != nil { + log.Errorf("get en tv detail error: %v", err) + } else { + name = fmt.Sprintf("%s %s", d.Name, en.Name) + } + } + //remove extra characters + re := regexp.MustCompile(`[^\p{L}\w\s]`) + name = re.ReplaceAllString(strings.ToLower(name), " ") + name = strings.Join(strings.Fields(name), " ") + year := strings.Split(d.FirstAirDate, "-")[0] + if year != "" { + name = fmt.Sprintf("%s (%s)", name, year) + } + + log.Infof("tv series of tmdb id %v suggestting name is %v", tmdbId, name) + return name, nil +} diff --git a/server/core/scheduler.go b/server/core/scheduler.go index 92682e8..47f47c4 100644 --- a/server/core/scheduler.go +++ b/server/core/scheduler.go @@ -23,6 +23,9 @@ func (c *Client) addSysCron() { c.downloadAllMovies() }) c.mustAddCron("0 0 */12 * * *", c.checkAllSeriesNewSeason) + c.mustAddCron("0 0/30 * * * *", func() { + c.periodicallyUpdateImportlist() + }) c.cron.Start() } diff --git a/server/importlist.go b/server/importlist.go new file mode 100644 index 0000000..35272a2 --- /dev/null +++ b/server/importlist.go @@ -0,0 +1,60 @@ +package server + +import ( + "fmt" + "polaris/ent" + "polaris/ent/importlist" + + "github.com/gin-gonic/gin" + "github.com/pkg/errors" +) + +func (s *Server) getAllImportLists(c *gin.Context) (interface{}, error) { + lists, err := s.db.GetAllImportLists() + return lists, err +} + +type addImportlistIn struct { + Name string `json:"name" binding:"required"` + Url string `json:"url"` + Type string `json:"type"` + Qulity string `json:"qulity"` + StorageId int `json:"storage_id"` +} + +func (s *Server) addImportlist(c *gin.Context) (interface{}, error) { + var in addImportlistIn + + if err := c.ShouldBindJSON(&in); err != nil { + return nil, errors.Wrap(err, "json") + } + st := s.db.GetStorage(in.StorageId) + if st == nil { + return nil, fmt.Errorf("storage id not exist: %v", in.StorageId) + } + err := s.db.AddImportlist(&ent.ImportList{ + Name: in.Name, + URL: in.Url, + Type: importlist.Type(in.Type), + Qulity: in.Qulity, + StorageID: in.StorageId, + }) + if err != nil { + return nil, err + } + return "success", nil +} + +type deleteImportlistIn struct { + ID int `json:"id"` +} + +func (s *Server) deleteImportList(c *gin.Context) (interface{}, error) { + var in deleteImportlistIn + + if err := c.ShouldBindJSON(&in); err != nil { + return nil, errors.Wrap(err, "json") + } + s.db.DeleteImportlist(in.ID) + return "sucess", nil +} diff --git a/server/server.go b/server/server.go index d9816d7..4375c6b 100644 --- a/server/server.go +++ b/server/server.go @@ -120,6 +120,12 @@ func (s *Server) Serve() error { notifier.DELETE("/id/:id", HttpHandler(s.DeleteNotificationClient)) notifier.POST("/add", HttpHandler(s.AddNotificationClient)) } + importlist := api.Group("/importlist") + { + importlist.GET("/", HttpHandler(s.getAllImportLists)) + importlist.POST("/add", HttpHandler(s.addImportlist)) + importlist.DELETE("/delete", HttpHandler(s.deleteImportList)) + } s.language = s.db.GetLanguage() return s.r.Run(":8080") @@ -132,7 +138,7 @@ func (s *Server) TMDB() (*tmdb.Client, error) { } proxy := s.db.GetSetting(db.SettingProxy) adult := s.db.GetSetting(db.SettingEnableTmdbAdultContent) - return tmdb.NewClient(api, proxy, adult=="true") + return tmdb.NewClient(api, proxy, adult == "true") } func (s *Server) MustTMDB() *tmdb.Client { diff --git a/server/storage.go b/server/storage.go index 7c6a3a0..06d691e 100644 --- a/server/storage.go +++ b/server/storage.go @@ -3,12 +3,10 @@ package server import ( "fmt" "polaris/db" - "regexp" "polaris/log" "polaris/pkg/storage" "strconv" - "strings" "github.com/gin-gonic/gin" "github.com/pkg/errors" @@ -61,31 +59,10 @@ func (s *Server) SuggestedSeriesFolderName(c *gin.Context) (interface{}, error) if err != nil { return nil, fmt.Errorf("id is not int: %v", ids) } - d, err := s.MustTMDB().GetTvDetails(id, s.language) + name, err := s.core.SuggestedSeriesFolderName(id) if err != nil { - return nil, errors.Wrap(err, "get tv details") + return nil, err } - - name := d.Name - - if s.language == db.LanguageCN { - en, err := s.MustTMDB().GetTvDetails(id, db.LanguageEN) - if err != nil { - log.Errorf("get en tv detail error: %v", err) - } else { - name = fmt.Sprintf("%s %s", d.Name, en.Name) - } - } - //remove extra characters - re := regexp.MustCompile(`[^\p{L}\w\s]`) - name = re.ReplaceAllString(strings.ToLower(name), " ") - name = strings.Join(strings.Fields(name), " ") - year := strings.Split(d.FirstAirDate, "-")[0] - if year != "" { - name = fmt.Sprintf("%s (%s)", name, year) - } - - log.Infof("tv series of tmdb id %v suggestting name is %v", id, name) return gin.H{"name": name}, nil } @@ -95,36 +72,9 @@ func (s *Server) SuggestedMovieFolderName(c *gin.Context) (interface{}, error) { if err != nil { return nil, fmt.Errorf("id is not int: %v", ids) } - d1, err := s.MustTMDB().GetMovieDetails(id, s.language) + name, err := s.core.SuggestedMovieFolderName(id) if err != nil { - return nil, errors.Wrap(err, "get movie details") + return nil, err } - name := d1.Title - - if isJav(d1) { - javid := s.getJavid(id) - if javid != "" { - return gin.H{"name": javid}, nil - } - } - - if s.language == db.LanguageCN { - en, err := s.MustTMDB().GetMovieDetails(id, db.LanguageEN) - if err != nil { - log.Errorf("get en movie detail error: %v", err) - } else { - name = fmt.Sprintf("%s %s", d1.Title, en.Title) - } - } - //remove extra characters - re := regexp.MustCompile(`[^\p{L}\w\s]`) - name = re.ReplaceAllString(strings.ToLower(name), " ") - name = strings.Join(strings.Fields(name), " ") - year := strings.Split(d1.ReleaseDate, "-")[0] - if year != "" { - name = fmt.Sprintf("%s (%s)", name, year) - } - - log.Infof("tv series of tmdb id %v suggestting name is %v", id, name) return gin.H{"name": name}, nil } diff --git a/server/watchlist.go b/server/watchlist.go index 8dd9ea2..06826f9 100644 --- a/server/watchlist.go +++ b/server/watchlist.go @@ -1,22 +1,16 @@ package server import ( - "fmt" - "io" - "net/http" "os" "path/filepath" "polaris/db" "polaris/ent" "polaris/ent/episode" "polaris/ent/media" - "polaris/ent/schema" "polaris/log" + "polaris/server/core" "strconv" - "strings" - "time" - tmdb "github.com/cyruzin/golang-tmdb" "github.com/gin-gonic/gin" "github.com/pkg/errors" ) @@ -73,245 +67,19 @@ type addWatchlistIn struct { } func (s *Server) AddTv2Watchlist(c *gin.Context) (interface{}, error) { - var in addWatchlistIn + var in core.AddWatchlistIn if err := c.ShouldBindJSON(&in); err != nil { return nil, errors.Wrap(err, "bind query") } - log.Debugf("add tv watchlist input %+v", in) - if in.Folder == "" { - return nil, errors.New("folder should be provided") - } - detailCn, err := s.MustTMDB().GetTvDetails(in.TmdbID, db.LanguageCN) - if err != nil { - return nil, errors.Wrap(err, "get tv detail") - } - var nameCn = detailCn.Name - - detailEn, _ := s.MustTMDB().GetTvDetails(in.TmdbID, db.LanguageEN) - var nameEn = detailEn.Name - var detail *tmdb.TVDetails - if s.language == "" || s.language == db.LanguageCN { - detail = detailCn - } else { - detail = detailEn - } - log.Infof("find detail for tv id %d: %v", in.TmdbID, detail) - - var epIds []int - for _, season := range detail.Seasons { - seasonId := season.SeasonNumber - se, err := s.MustTMDB().GetSeasonDetails(int(detail.ID), seasonId, s.language) - if err != nil { - log.Errorf("get season detail (%s) error: %v", detail.Name, err) - continue - } - for _, ep := range se.Episodes { - shouldMonitor := false - //如果设置下载往期剧集,则监控所有剧集。如果没有则监控未上映的剧集,考虑时差等问题留24h余量 - if in.DownloadHistoryEpisodes { - shouldMonitor = true - } else { - t, err := time.Parse("2006-01-02", ep.AirDate) - if err != nil { - log.Error("air date not known, will monitor: %v", ep.AirDate) - shouldMonitor = true - - } else { - if time.Since(t) < 24*time.Hour { //monitor episode air 24h before now - shouldMonitor = true - } - } - } - - epid, err := s.db.SaveEposideDetail(&ent.Episode{ - SeasonNumber: seasonId, - EpisodeNumber: ep.EpisodeNumber, - Title: ep.Name, - Overview: ep.Overview, - AirDate: ep.AirDate, - Monitored: shouldMonitor, - }) - if err != nil { - log.Errorf("save episode info error: %v", err) - continue - } - epIds = append(epIds, epid) - } - } - m := &ent.Media{ - TmdbID: int(detail.ID), - ImdbID: detail.IMDbID, - MediaType: media.MediaTypeTv, - NameCn: nameCn, - NameEn: nameEn, - OriginalName: detail.OriginalName, - Overview: detail.Overview, - AirDate: detail.FirstAirDate, - Resolution: media.Resolution(in.Resolution), - StorageID: in.StorageID, - TargetDir: in.Folder, - DownloadHistoryEpisodes: in.DownloadHistoryEpisodes, - Limiter: schema.MediaLimiter{SizeMin: in.SizeMin, SizeMax: in.SizeMax}, - Extras: schema.MediaExtras{ - OriginalLanguage: detail.OriginalLanguage, - Genres: detail.Genres, - }, - } - - r, err := s.db.AddMediaWatchlist(m, epIds) - if err != nil { - return nil, errors.Wrap(err, "add to list") - } - go func() { - if err := s.downloadPoster(detail.PosterPath, r.ID); err != nil { - log.Errorf("download poster error: %v", err) - } - if err := s.downloadBackdrop(detail.BackdropPath, r.ID); err != nil { - log.Errorf("download poster error: %v", err) - } - if err := s.core.CheckDownloadedSeriesFiles(r); err != nil { - log.Errorf("check downloaded files error: %v", err) - } - - }() - - log.Infof("add tv %s to watchlist success", detail.Name) - return nil, nil -} - -func isJav(detail *tmdb.MovieDetails) bool { - if detail.Adult && len(detail.ProductionCountries) > 0 && strings.ToUpper(detail.ProductionCountries[0].Iso3166_1) == "JP" { - return true - } - return false -} - -func (s *Server) getJavid(id int) string { - alters, err := s.MustTMDB().GetMovieAlternativeTitles(id, s.language) - if err != nil { - return "" - } - for _, t := range alters.Titles { - if t.Iso3166_1 == "JP" && t.Type == "" { - return t.Title - } - } - return "" + return s.core.AddTv2Watchlist(in) } func (s *Server) AddMovie2Watchlist(c *gin.Context) (interface{}, error) { - var in addWatchlistIn + var in core.AddWatchlistIn if err := c.ShouldBindJSON(&in); err != nil { return nil, errors.Wrap(err, "bind query") } - log.Infof("add movie watchlist input: %+v", in) - detailCn, err := s.MustTMDB().GetMovieDetails(in.TmdbID, db.LanguageCN) - if err != nil { - return nil, errors.Wrap(err, "get movie detail") - } - var nameCn = detailCn.Title - - detailEn, _ := s.MustTMDB().GetMovieDetails(in.TmdbID, db.LanguageEN) - var nameEn = detailEn.Title - var detail *tmdb.MovieDetails - if s.language == "" || s.language == db.LanguageCN { - detail = detailCn - } else { - detail = detailEn - } - log.Infof("find detail for movie id %d: %v", in.TmdbID, detail) - - epid, err := s.db.SaveEposideDetail(&ent.Episode{ - SeasonNumber: 1, - EpisodeNumber: 1, - Title: "dummy episode for movies", - Overview: "dummy episode for movies", - AirDate: detail.ReleaseDate, - Monitored: true, - }) - if err != nil { - return nil, errors.Wrap(err, "add dummy episode") - } - log.Infof("added dummy episode for movie: %v", nameEn) - - movie := ent.Media{ - TmdbID: int(detail.ID), - ImdbID: detail.IMDbID, - MediaType: media.MediaTypeMovie, - NameCn: nameCn, - NameEn: nameEn, - OriginalName: detail.OriginalTitle, - Overview: detail.Overview, - AirDate: detail.ReleaseDate, - Resolution: media.Resolution(in.Resolution), - StorageID: in.StorageID, - TargetDir: in.Folder, - Limiter: schema.MediaLimiter{SizeMin: in.SizeMin, SizeMax: in.SizeMax}, - } - - extras := schema.MediaExtras{ - IsAdultMovie: detail.Adult, - OriginalLanguage: detail.OriginalLanguage, - Genres: detail.Genres, - } - if isJav(detail) { - javid := s.getJavid(in.TmdbID) - extras.JavId = javid - } - - movie.Extras = extras - r, err := s.db.AddMediaWatchlist(&movie, []int{epid}) - if err != nil { - return nil, errors.Wrap(err, "add to list") - } - go func() { - if err := s.downloadPoster(detail.PosterPath, r.ID); err != nil { - log.Errorf("download poster error: %v", err) - } - if err := s.downloadBackdrop(detail.BackdropPath, r.ID); err != nil { - log.Errorf("download backdrop error: %v", err) - } - }() - - log.Infof("add movie %s to watchlist success", detail.Title) - return nil, nil - -} - -func (s *Server) downloadBackdrop(path string, mediaID int) error { - url := "https://image.tmdb.org/t/p/original" + path - return s.downloadImage(url, mediaID, "backdrop.jpg") -} - -func (s *Server) downloadPoster(path string, mediaID int) error { - var url = "https://image.tmdb.org/t/p/original" + path - - return s.downloadImage(url, mediaID, "poster.jpg") -} - -func (s *Server) downloadImage(url string, mediaID int, name string) error { - - log.Infof("try to download image: %v", url) - var resp, err = http.Get(url) - if err != nil { - return errors.Wrap(err, "http get") - } - targetDir := fmt.Sprintf("%v/%d", db.ImgPath, mediaID) - os.MkdirAll(targetDir, 0777) - //ext := filepath.Ext(path) - targetFile := filepath.Join(targetDir, name) - f, err := os.Create(targetFile) - if err != nil { - return errors.Wrap(err, "new file") - } - defer f.Close() - _, err = io.Copy(f, resp.Body) - if err != nil { - return errors.Wrap(err, "copy http response") - } - log.Infof("image successfully downlaoded: %v", targetFile) - return nil - + return s.core.AddMovie2Watchlist(in) } type MediaWithStatus struct { diff --git a/ui/lib/calendar.dart b/ui/lib/calendar.dart new file mode 100644 index 0000000..bebf89f --- /dev/null +++ b/ui/lib/calendar.dart @@ -0,0 +1,60 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:table_calendar/table_calendar.dart'; + +class Calendar extends ConsumerStatefulWidget { + @override + ConsumerState createState() { + return _CalendarSate(); + } +} + +class _CalendarSate extends ConsumerState { + DateTime? _selectedDay; + DateTime _focusedDay = DateTime.now(); + CalendarFormat _calendarFormat = CalendarFormat.month; + + @override + Widget build(BuildContext context) { + return TableCalendar( + locale: "zh_CN", + firstDay: DateTime.utc(2010, 10, 16), + lastDay: DateTime.utc(2030, 3, 14), + focusedDay: _focusedDay, + selectedDayPredicate: (day) { + return isSameDay(_selectedDay, day); + }, + onDaySelected: (selectedDay, focusedDay) { + setState(() { + _selectedDay = selectedDay; + _focusedDay = focusedDay; // update `_focusedDay` here as well + }); + }, + calendarFormat: _calendarFormat, + onFormatChanged: (format) { + setState(() { + _calendarFormat = format; + }); + }, + + //locale: "zh_CN", + //eventLoader: (day) {}, + ); + } +} + +showCalendar(BuildContext context) { + return showDialog( + context: context, + barrierDismissible: true, + builder: (BuildContext context) { + return AlertDialog( + //title: Text("资源"), + content: SizedBox( + width: MediaQuery.of(context).size.width * 0.7, + height: MediaQuery.of(context).size.height * 0.6, + child: Calendar()), + ); + }, + ); +} diff --git a/ui/lib/main.dart b/ui/lib/main.dart index 9ea75fa..d8f4fba 100644 --- a/ui/lib/main.dart +++ b/ui/lib/main.dart @@ -2,7 +2,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_adaptive_scaffold/flutter_adaptive_scaffold.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; +import 'package:intl/date_symbol_data_local.dart'; import 'package:ui/activity.dart'; +import 'package:ui/calendar.dart'; import 'package:ui/login_page.dart'; import 'package:ui/movie_watchlist.dart'; import 'package:ui/providers/APIs.dart'; @@ -14,7 +16,7 @@ import 'package:ui/welcome_page.dart'; import 'package:ui/widgets/utils.dart'; void main() { - runApp(const MyApp()); + initializeDateFormatting().then((_) => runApp(MyApp())); } class MyApp extends ConsumerStatefulWidget { @@ -219,6 +221,9 @@ class _MainSkeletonState extends State { (BuildContext context, SearchController controller) { return [Text("dadada")]; }), + IconButton( + onPressed: () => showCalendar(context), + icon: Icon(Icons.calendar_month)), MenuAnchor( menuChildren: [ MenuItemButton( diff --git a/ui/lib/providers/APIs.dart b/ui/lib/providers/APIs.dart index 9d94917..bc3ef84 100644 --- a/ui/lib/providers/APIs.dart +++ b/ui/lib/providers/APIs.dart @@ -36,6 +36,9 @@ class APIs { static final logFilesUrl = "$_baseUrl/api/v1/setting/logfiles"; static final aboutUrl = "$_baseUrl/api/v1/setting/about"; static final changeMonitoringUrl = "$_baseUrl/api/v1/setting/monitoring"; + static final addImportlistUrl = "$_baseUrl/api/v1/importlist/add"; + static final deleteImportlistUrl = "$_baseUrl/api/v1/importlist/delete"; + static final getAllImportlists = "$_baseUrl/api/v1/importlist/"; static final notifierAllUrl = "$_baseUrl/api/v1/notifier/all"; static final notifierDeleteUrl = "$_baseUrl/api/v1/notifier/id/"; diff --git a/ui/lib/providers/settings.dart b/ui/lib/providers/settings.dart index 087bddf..00ef5f7 100644 --- a/ui/lib/providers/settings.dart +++ b/ui/lib/providers/settings.dart @@ -21,6 +21,10 @@ var storageSettingProvider = AsyncNotifierProvider.autoDispose>( StorageSettingData.new); +var importlistProvider = + AsyncNotifierProvider.autoDispose>( + ImportListData.new); + class EditSettingData extends AutoDisposeAsyncNotifier { @override FutureOr build() async { @@ -72,7 +76,7 @@ class GeneralSetting { downloadDIr: json["download_dir"], logLevel: json["log_level"], proxy: json["proxy"], - enableAdult: json["enable_adult_content"]??false, + enableAdult: json["enable_adult_content"] ?? false, allowQiangban: json["allow_qiangban"] ?? false, enableNfo: json["enable_nfo"] ?? false, enablePlexmatch: json["enable_plexmatch"] ?? false); @@ -413,3 +417,77 @@ class About { ); } } + +class ImportList { + final int? id; + final String? name; + final String? url; + final String? qulity; + final int? storageId; + final String? type; + ImportList({ + this.id, + this.name, + this.url, + this.qulity, + this.storageId, + this.type, + }); + + factory ImportList.fromJson(Map json) { + return ImportList( + id: json["id"], + name: json["name"], + url: json["url"], + qulity: json["qulity"], + type: json["type"], + storageId: json["storage_id"]); + } + + Map tojson() => { + "name": name, + "url": url, + "qulity": qulity, + "type": type, + "storage_id": storageId + }; +} + +class ImportListData extends AutoDisposeAsyncNotifier> { + @override + FutureOr> build() async { + final dio = APIs.getDio(); + var resp = await dio.get(APIs.getAllImportlists); + var sp = ServerResponse.fromJson(resp.data); + if (sp.code != 0) { + throw sp.message; + } + List list = List.empty(growable: true); + + for (var item in sp.data as List) { + var il = ImportList.fromJson(item); + list.add(il); + } + return list; + } + + addImportlist(ImportList il) async { + final dio = APIs.getDio(); + var resp = await dio.post(APIs.addImportlistUrl, data: il.tojson()); + var sp = ServerResponse.fromJson(resp.data); + if (sp.code != 0) { + throw sp.message; + } + ref.invalidateSelf(); + } + + deleteimportlist(int id) async { + final dio = APIs.getDio(); + var resp = await dio.post(APIs.deleteImportlistUrl, data: {"id": id}); + var sp = ServerResponse.fromJson(resp.data); + if (sp.code != 0) { + throw sp.message; + } + ref.invalidateSelf(); + } +} diff --git a/ui/lib/settings/importlist.dart b/ui/lib/settings/importlist.dart new file mode 100644 index 0000000..e75aec7 --- /dev/null +++ b/ui/lib/settings/importlist.dart @@ -0,0 +1,122 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_form_builder/flutter_form_builder.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:form_builder_validators/form_builder_validators.dart'; +import 'package:ui/providers/settings.dart'; +import 'package:ui/settings/dialog.dart'; +import 'package:ui/widgets/progress_indicator.dart'; +import 'package:ui/widgets/widgets.dart'; + +class Importlist extends ConsumerStatefulWidget { + const Importlist({super.key}); + + @override + ConsumerState createState() { + return _ImportlistState(); + } +} + +class _ImportlistState extends ConsumerState { + @override + Widget build(BuildContext context) { + var importlists = ref.watch(importlistProvider); + + return importlists.when( + data: (value) => Wrap( + children: List.generate(value.length + 1, (i) { + if (i < value.length) { + var indexer = value[i]; + return SettingsCard( + onTap: () => showImportlistDetails(indexer), + child: Text(indexer.name ?? "")); + } + return SettingsCard( + onTap: () => showImportlistDetails(ImportList()), + child: const Icon(Icons.add)); + }), + ), + error: (err, trace) => Text("$err"), + loading: () => const MyProgressIndicator()); + } + + Future showImportlistDetails(ImportList list) { + final _formKey = GlobalKey(); + + var body = FormBuilder( + key: _formKey, + initialValue: { + "name": list.name, + "qulity": list.qulity, + "storage_id": list.storageId + }, + child: Column( + children: [ + FormBuilderTextField( + name: "name", + decoration: Commons.requiredTextFieldStyle(text: "名称"), + autovalidateMode: AutovalidateMode.onUserInteraction, + validator: FormBuilderValidators.required(), + ), + FormBuilderTextField( + name: "url", + decoration: Commons.requiredTextFieldStyle(text: "地址"), + autovalidateMode: AutovalidateMode.onUserInteraction, + validator: FormBuilderValidators.required(), + ), + FormBuilderDropdown( + name: "qulity", + decoration: const InputDecoration(labelText: "清晰度"), + items: const [ + DropdownMenuItem(value: "720p", child: Text("720p")), + DropdownMenuItem(value: "1080p", child: Text("1080p")), + DropdownMenuItem(value: "2160p", child: Text("2160p")), + ], + ), + Consumer( + builder: (context, ref, child) { + var storage = ref.watch(storageSettingProvider); + return storage.when( + data: (v) { + return FormBuilderDropdown( + name: "storage_id", + decoration: const InputDecoration(labelText: "存储"), + items: List.generate( + v.length, + (i) => DropdownMenuItem( + value: v[i].id, + child: Text(v[i].name!), + )), + ); + }, + error: (err, trace) => Text("$err"), + loading: () => const MyProgressIndicator()); + }, + ), + ], + ), + ); + onDelete() async { + return ref.read(importlistProvider.notifier).deleteimportlist(list.id!); + } + + onSubmit() async { + if (_formKey.currentState!.saveAndValidate()) { + var values = _formKey.currentState!.value; + + return ref.read(importlistProvider.notifier).addImportlist(ImportList( + id: list.id, + name: values["name"], + url: values["url"], + type: "plex", + qulity: values["qulity"], + storageId: values["storage_id"], + )); + } else { + throw "validation_error"; + } + } + + return showSettingDialog( + context, "导入列表", list.id != null, body, onSubmit, onDelete); + } +} diff --git a/ui/lib/settings/settings.dart b/ui/lib/settings/settings.dart index 775e7d1..45ab963 100644 --- a/ui/lib/settings/settings.dart +++ b/ui/lib/settings/settings.dart @@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:ui/settings/auth.dart'; import 'package:ui/settings/downloader.dart'; import 'package:ui/settings/general.dart'; +import 'package:ui/settings/importlist.dart'; import 'package:ui/settings/indexer.dart'; import 'package:ui/settings/notifier.dart'; import 'package:ui/settings/storage.dart'; @@ -21,49 +22,25 @@ class _SystemSettingsPageState extends ConsumerState { @override Widget build(BuildContext context) { return ListView( - children: const [ - ExpansionTile( - expandedAlignment: Alignment.centerLeft, - childrenPadding: EdgeInsets.fromLTRB(20, 0, 20, 0), - initiallyExpanded: true, - title: Text("常规"), - children: [GeneralSettings()], - ), - ExpansionTile( - expandedAlignment: Alignment.centerLeft, - childrenPadding: EdgeInsets.fromLTRB(20, 0, 20, 0), - initiallyExpanded: false, - title: Text("索引器"), - children: [IndexerSettings()], - ), - ExpansionTile( - expandedAlignment: Alignment.centerLeft, - childrenPadding: EdgeInsets.fromLTRB(20, 0, 20, 0), - initiallyExpanded: false, - title: Text("下载器"), - children: [DownloaderSettings()], - ), - ExpansionTile( - expandedAlignment: Alignment.centerLeft, - childrenPadding: EdgeInsets.fromLTRB(20, 0, 20, 0), - initiallyExpanded: false, - title: Text("存储"), - children: [StorageSettings()], - ), - ExpansionTile( - expandedAlignment: Alignment.centerLeft, - childrenPadding: EdgeInsets.fromLTRB(20, 0, 20, 0), - initiallyExpanded: false, - title: Text("通知客户端"), - children: [NotifierSettings()], - ), - ExpansionTile( - childrenPadding: EdgeInsets.fromLTRB(20, 0, 20, 0), - initiallyExpanded: false, - title: Text("认证"), - children: [AuthSettings()], - ), + children: [ + getExpansionTile("常规", const GeneralSettings()), + getExpansionTile("索引器", const IndexerSettings()), + getExpansionTile("下载器", const DownloaderSettings()), + getExpansionTile("存储", const StorageSettings()), + getExpansionTile("通知客户端", const NotifierSettings()), + getExpansionTile("导入列表", const Importlist()), + getExpansionTile("认证", const AuthSettings()) ], ); } + + Widget getExpansionTile(String name, Widget body) { + return ExpansionTile( + childrenPadding: const EdgeInsets.fromLTRB(20, 0, 20, 0), + expandedAlignment: Alignment.topLeft, + initiallyExpanded: false, + title: Text(name), + children: [body], + ); + } } diff --git a/ui/pubspec.lock b/ui/pubspec.lock index f980199..06972e2 100644 --- a/ui/pubspec.lock +++ b/ui/pubspec.lock @@ -365,6 +365,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "3.2.0" + simple_gesture_detector: + dependency: transitive + description: + name: simple_gesture_detector + sha256: ba2cd5af24ff20a0b8d609cec3f40e5b0744d2a71804a2616ae086b9c19d19a3 + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.2.1" sky_engine: dependency: transitive description: flutter @@ -410,6 +418,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "1.2.0" + table_calendar: + dependency: "direct main" + description: + name: table_calendar + sha256: "4ca32b2fc919452c9974abd4c6ea611a63e33b9e4f0b8c38dba3ac1f4a6549d1" + url: "https://pub.flutter-io.cn" + source: hosted + version: "3.1.2" term_glyph: dependency: transitive description: @@ -518,10 +534,10 @@ packages: dependency: transitive description: name: vm_service - sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" url: "https://pub.flutter-io.cn" source: hosted - version: "14.2.4" + version: "14.2.5" web: dependency: transitive description: diff --git a/ui/pubspec.yaml b/ui/pubspec.yaml index 816dce6..f551aa8 100644 --- a/ui/pubspec.yaml +++ b/ui/pubspec.yaml @@ -46,6 +46,7 @@ dependencies: form_builder_validators: ^11.0.0 url_launcher: ^6.3.0 timeago: ^3.7.0 + table_calendar: ^3.1.2 dev_dependencies: flutter_test: