mirror of
https://github.com/simon-ding/polaris.git
synced 2026-03-09 19:20:46 +08:00
welcome page update
This commit is contained in:
9
db/db.go
9
db/db.go
@@ -3,9 +3,11 @@ package db
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"polaris/ent"
|
||||
"polaris/ent/downloadclients"
|
||||
"polaris/ent/indexers"
|
||||
"polaris/ent/series"
|
||||
"polaris/ent/settings"
|
||||
"polaris/log"
|
||||
|
||||
@@ -58,18 +60,23 @@ func (c *Client) GetLanguage() string {
|
||||
lang := c.GetSetting(SettingLanguage)
|
||||
log.Infof("get application language: %s", lang)
|
||||
if lang == "" {
|
||||
return "zh_CN"
|
||||
return "zh-CN"
|
||||
}
|
||||
return lang
|
||||
}
|
||||
|
||||
func (c *Client) AddWatchlist(path string, detail *tmdb.TVDetails) error {
|
||||
count := c.ent.Series.Query().Where(series.TmdbID(int(detail.ID))).CountX(context.Background())
|
||||
if (count > 0) {
|
||||
return fmt.Errorf("tv series %s already in watchlist", detail.Name)
|
||||
}
|
||||
_, err := c.ent.Series.Create().
|
||||
SetTmdbID(int(detail.ID)).
|
||||
SetPath(path).
|
||||
SetOverview(detail.Overview).
|
||||
SetTitle(detail.Name).
|
||||
SetOriginalName(detail.OriginalName).
|
||||
SetPosterPath(detail.PosterPath).
|
||||
Save(context.TODO())
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -78,11 +78,12 @@ var (
|
||||
SeriesColumns = []*schema.Column{
|
||||
{Name: "id", Type: field.TypeInt, Increment: true},
|
||||
{Name: "tmdb_id", Type: field.TypeInt},
|
||||
{Name: "imdb_id", Type: field.TypeString},
|
||||
{Name: "imdb_id", Type: field.TypeString, Nullable: true},
|
||||
{Name: "title", Type: field.TypeString},
|
||||
{Name: "original_name", Type: field.TypeString},
|
||||
{Name: "overview", Type: field.TypeString},
|
||||
{Name: "path", Type: field.TypeString},
|
||||
{Name: "poster_path", Type: field.TypeString, Nullable: true},
|
||||
}
|
||||
// SeriesTable holds the schema information for the "series" table.
|
||||
SeriesTable = &schema.Table{
|
||||
|
||||
@@ -2749,6 +2749,7 @@ type SeriesMutation struct {
|
||||
original_name *string
|
||||
overview *string
|
||||
_path *string
|
||||
poster_path *string
|
||||
clearedFields map[string]struct{}
|
||||
done bool
|
||||
oldValue func(context.Context) (*Series, error)
|
||||
@@ -2940,9 +2941,22 @@ func (m *SeriesMutation) OldImdbID(ctx context.Context) (v string, err error) {
|
||||
return oldValue.ImdbID, nil
|
||||
}
|
||||
|
||||
// ClearImdbID clears the value of the "imdb_id" field.
|
||||
func (m *SeriesMutation) ClearImdbID() {
|
||||
m.imdb_id = nil
|
||||
m.clearedFields[series.FieldImdbID] = struct{}{}
|
||||
}
|
||||
|
||||
// ImdbIDCleared returns if the "imdb_id" field was cleared in this mutation.
|
||||
func (m *SeriesMutation) ImdbIDCleared() bool {
|
||||
_, ok := m.clearedFields[series.FieldImdbID]
|
||||
return ok
|
||||
}
|
||||
|
||||
// ResetImdbID resets all changes to the "imdb_id" field.
|
||||
func (m *SeriesMutation) ResetImdbID() {
|
||||
m.imdb_id = nil
|
||||
delete(m.clearedFields, series.FieldImdbID)
|
||||
}
|
||||
|
||||
// SetTitle sets the "title" field.
|
||||
@@ -3089,6 +3103,55 @@ func (m *SeriesMutation) ResetPath() {
|
||||
m._path = nil
|
||||
}
|
||||
|
||||
// SetPosterPath sets the "poster_path" field.
|
||||
func (m *SeriesMutation) SetPosterPath(s string) {
|
||||
m.poster_path = &s
|
||||
}
|
||||
|
||||
// PosterPath returns the value of the "poster_path" field in the mutation.
|
||||
func (m *SeriesMutation) PosterPath() (r string, exists bool) {
|
||||
v := m.poster_path
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
return *v, true
|
||||
}
|
||||
|
||||
// OldPosterPath returns the old "poster_path" field's value of the Series entity.
|
||||
// If the Series 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 *SeriesMutation) OldPosterPath(ctx context.Context) (v string, err error) {
|
||||
if !m.op.Is(OpUpdateOne) {
|
||||
return v, errors.New("OldPosterPath is only allowed on UpdateOne operations")
|
||||
}
|
||||
if m.id == nil || m.oldValue == nil {
|
||||
return v, errors.New("OldPosterPath requires an ID field in the mutation")
|
||||
}
|
||||
oldValue, err := m.oldValue(ctx)
|
||||
if err != nil {
|
||||
return v, fmt.Errorf("querying old value for OldPosterPath: %w", err)
|
||||
}
|
||||
return oldValue.PosterPath, nil
|
||||
}
|
||||
|
||||
// ClearPosterPath clears the value of the "poster_path" field.
|
||||
func (m *SeriesMutation) ClearPosterPath() {
|
||||
m.poster_path = nil
|
||||
m.clearedFields[series.FieldPosterPath] = struct{}{}
|
||||
}
|
||||
|
||||
// PosterPathCleared returns if the "poster_path" field was cleared in this mutation.
|
||||
func (m *SeriesMutation) PosterPathCleared() bool {
|
||||
_, ok := m.clearedFields[series.FieldPosterPath]
|
||||
return ok
|
||||
}
|
||||
|
||||
// ResetPosterPath resets all changes to the "poster_path" field.
|
||||
func (m *SeriesMutation) ResetPosterPath() {
|
||||
m.poster_path = nil
|
||||
delete(m.clearedFields, series.FieldPosterPath)
|
||||
}
|
||||
|
||||
// Where appends a list predicates to the SeriesMutation builder.
|
||||
func (m *SeriesMutation) Where(ps ...predicate.Series) {
|
||||
m.predicates = append(m.predicates, ps...)
|
||||
@@ -3123,7 +3186,7 @@ func (m *SeriesMutation) Type() string {
|
||||
// order to get all numeric fields that were incremented/decremented, call
|
||||
// AddedFields().
|
||||
func (m *SeriesMutation) Fields() []string {
|
||||
fields := make([]string, 0, 6)
|
||||
fields := make([]string, 0, 7)
|
||||
if m.tmdb_id != nil {
|
||||
fields = append(fields, series.FieldTmdbID)
|
||||
}
|
||||
@@ -3142,6 +3205,9 @@ func (m *SeriesMutation) Fields() []string {
|
||||
if m._path != nil {
|
||||
fields = append(fields, series.FieldPath)
|
||||
}
|
||||
if m.poster_path != nil {
|
||||
fields = append(fields, series.FieldPosterPath)
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
@@ -3162,6 +3228,8 @@ func (m *SeriesMutation) Field(name string) (ent.Value, bool) {
|
||||
return m.Overview()
|
||||
case series.FieldPath:
|
||||
return m.Path()
|
||||
case series.FieldPosterPath:
|
||||
return m.PosterPath()
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
@@ -3183,6 +3251,8 @@ func (m *SeriesMutation) OldField(ctx context.Context, name string) (ent.Value,
|
||||
return m.OldOverview(ctx)
|
||||
case series.FieldPath:
|
||||
return m.OldPath(ctx)
|
||||
case series.FieldPosterPath:
|
||||
return m.OldPosterPath(ctx)
|
||||
}
|
||||
return nil, fmt.Errorf("unknown Series field %s", name)
|
||||
}
|
||||
@@ -3234,6 +3304,13 @@ func (m *SeriesMutation) SetField(name string, value ent.Value) error {
|
||||
}
|
||||
m.SetPath(v)
|
||||
return nil
|
||||
case series.FieldPosterPath:
|
||||
v, ok := value.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||
}
|
||||
m.SetPosterPath(v)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unknown Series field %s", name)
|
||||
}
|
||||
@@ -3278,7 +3355,14 @@ func (m *SeriesMutation) AddField(name string, value ent.Value) error {
|
||||
// ClearedFields returns all nullable fields that were cleared during this
|
||||
// mutation.
|
||||
func (m *SeriesMutation) ClearedFields() []string {
|
||||
return nil
|
||||
var fields []string
|
||||
if m.FieldCleared(series.FieldImdbID) {
|
||||
fields = append(fields, series.FieldImdbID)
|
||||
}
|
||||
if m.FieldCleared(series.FieldPosterPath) {
|
||||
fields = append(fields, series.FieldPosterPath)
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
// FieldCleared returns a boolean indicating if a field with the given name was
|
||||
@@ -3291,6 +3375,14 @@ func (m *SeriesMutation) FieldCleared(name string) bool {
|
||||
// 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 *SeriesMutation) ClearField(name string) error {
|
||||
switch name {
|
||||
case series.FieldImdbID:
|
||||
m.ClearImdbID()
|
||||
return nil
|
||||
case series.FieldPosterPath:
|
||||
m.ClearPosterPath()
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unknown Series nullable field %s", name)
|
||||
}
|
||||
|
||||
@@ -3316,6 +3408,9 @@ func (m *SeriesMutation) ResetField(name string) error {
|
||||
case series.FieldPath:
|
||||
m.ResetPath()
|
||||
return nil
|
||||
case series.FieldPosterPath:
|
||||
m.ResetPosterPath()
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("unknown Series field %s", name)
|
||||
}
|
||||
|
||||
@@ -14,11 +14,12 @@ type Series struct {
|
||||
func (Series) Fields() []ent.Field {
|
||||
return []ent.Field{
|
||||
field.Int("tmdb_id"),
|
||||
field.String("imdb_id"),
|
||||
field.String("imdb_id").Optional(),
|
||||
field.String("title"),
|
||||
field.String("original_name"),
|
||||
field.String("overview"),
|
||||
field.String("path"),
|
||||
field.String("poster_path").Optional(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,9 @@ type Series struct {
|
||||
// Overview holds the value of the "overview" field.
|
||||
Overview string `json:"overview,omitempty"`
|
||||
// Path holds the value of the "path" field.
|
||||
Path string `json:"path,omitempty"`
|
||||
Path string `json:"path,omitempty"`
|
||||
// PosterPath holds the value of the "poster_path" field.
|
||||
PosterPath string `json:"poster_path,omitempty"`
|
||||
selectValues sql.SelectValues
|
||||
}
|
||||
|
||||
@@ -38,7 +40,7 @@ func (*Series) scanValues(columns []string) ([]any, error) {
|
||||
switch columns[i] {
|
||||
case series.FieldID, series.FieldTmdbID:
|
||||
values[i] = new(sql.NullInt64)
|
||||
case series.FieldImdbID, series.FieldTitle, series.FieldOriginalName, series.FieldOverview, series.FieldPath:
|
||||
case series.FieldImdbID, series.FieldTitle, series.FieldOriginalName, series.FieldOverview, series.FieldPath, series.FieldPosterPath:
|
||||
values[i] = new(sql.NullString)
|
||||
default:
|
||||
values[i] = new(sql.UnknownType)
|
||||
@@ -97,6 +99,12 @@ func (s *Series) assignValues(columns []string, values []any) error {
|
||||
} else if value.Valid {
|
||||
s.Path = value.String
|
||||
}
|
||||
case series.FieldPosterPath:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field poster_path", values[i])
|
||||
} else if value.Valid {
|
||||
s.PosterPath = value.String
|
||||
}
|
||||
default:
|
||||
s.selectValues.Set(columns[i], values[i])
|
||||
}
|
||||
@@ -150,6 +158,9 @@ func (s *Series) String() string {
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("path=")
|
||||
builder.WriteString(s.Path)
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("poster_path=")
|
||||
builder.WriteString(s.PosterPath)
|
||||
builder.WriteByte(')')
|
||||
return builder.String()
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ const (
|
||||
FieldOverview = "overview"
|
||||
// FieldPath holds the string denoting the path field in the database.
|
||||
FieldPath = "path"
|
||||
// FieldPosterPath holds the string denoting the poster_path field in the database.
|
||||
FieldPosterPath = "poster_path"
|
||||
// Table holds the table name of the series in the database.
|
||||
Table = "series"
|
||||
)
|
||||
@@ -36,6 +38,7 @@ var Columns = []string{
|
||||
FieldOriginalName,
|
||||
FieldOverview,
|
||||
FieldPath,
|
||||
FieldPosterPath,
|
||||
}
|
||||
|
||||
// ValidColumn reports if the column name is valid (part of the table columns).
|
||||
@@ -85,3 +88,8 @@ func ByOverview(opts ...sql.OrderTermOption) OrderOption {
|
||||
func ByPath(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldPath, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByPosterPath orders the results by the poster_path field.
|
||||
func ByPosterPath(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldPosterPath, opts...).ToFunc()
|
||||
}
|
||||
|
||||
@@ -83,6 +83,11 @@ func Path(v string) predicate.Series {
|
||||
return predicate.Series(sql.FieldEQ(FieldPath, v))
|
||||
}
|
||||
|
||||
// PosterPath applies equality check predicate on the "poster_path" field. It's identical to PosterPathEQ.
|
||||
func PosterPath(v string) predicate.Series {
|
||||
return predicate.Series(sql.FieldEQ(FieldPosterPath, v))
|
||||
}
|
||||
|
||||
// TmdbIDEQ applies the EQ predicate on the "tmdb_id" field.
|
||||
func TmdbIDEQ(v int) predicate.Series {
|
||||
return predicate.Series(sql.FieldEQ(FieldTmdbID, v))
|
||||
@@ -178,6 +183,16 @@ func ImdbIDHasSuffix(v string) predicate.Series {
|
||||
return predicate.Series(sql.FieldHasSuffix(FieldImdbID, v))
|
||||
}
|
||||
|
||||
// ImdbIDIsNil applies the IsNil predicate on the "imdb_id" field.
|
||||
func ImdbIDIsNil() predicate.Series {
|
||||
return predicate.Series(sql.FieldIsNull(FieldImdbID))
|
||||
}
|
||||
|
||||
// ImdbIDNotNil applies the NotNil predicate on the "imdb_id" field.
|
||||
func ImdbIDNotNil() predicate.Series {
|
||||
return predicate.Series(sql.FieldNotNull(FieldImdbID))
|
||||
}
|
||||
|
||||
// ImdbIDEqualFold applies the EqualFold predicate on the "imdb_id" field.
|
||||
func ImdbIDEqualFold(v string) predicate.Series {
|
||||
return predicate.Series(sql.FieldEqualFold(FieldImdbID, v))
|
||||
@@ -448,6 +463,81 @@ func PathContainsFold(v string) predicate.Series {
|
||||
return predicate.Series(sql.FieldContainsFold(FieldPath, v))
|
||||
}
|
||||
|
||||
// PosterPathEQ applies the EQ predicate on the "poster_path" field.
|
||||
func PosterPathEQ(v string) predicate.Series {
|
||||
return predicate.Series(sql.FieldEQ(FieldPosterPath, v))
|
||||
}
|
||||
|
||||
// PosterPathNEQ applies the NEQ predicate on the "poster_path" field.
|
||||
func PosterPathNEQ(v string) predicate.Series {
|
||||
return predicate.Series(sql.FieldNEQ(FieldPosterPath, v))
|
||||
}
|
||||
|
||||
// PosterPathIn applies the In predicate on the "poster_path" field.
|
||||
func PosterPathIn(vs ...string) predicate.Series {
|
||||
return predicate.Series(sql.FieldIn(FieldPosterPath, vs...))
|
||||
}
|
||||
|
||||
// PosterPathNotIn applies the NotIn predicate on the "poster_path" field.
|
||||
func PosterPathNotIn(vs ...string) predicate.Series {
|
||||
return predicate.Series(sql.FieldNotIn(FieldPosterPath, vs...))
|
||||
}
|
||||
|
||||
// PosterPathGT applies the GT predicate on the "poster_path" field.
|
||||
func PosterPathGT(v string) predicate.Series {
|
||||
return predicate.Series(sql.FieldGT(FieldPosterPath, v))
|
||||
}
|
||||
|
||||
// PosterPathGTE applies the GTE predicate on the "poster_path" field.
|
||||
func PosterPathGTE(v string) predicate.Series {
|
||||
return predicate.Series(sql.FieldGTE(FieldPosterPath, v))
|
||||
}
|
||||
|
||||
// PosterPathLT applies the LT predicate on the "poster_path" field.
|
||||
func PosterPathLT(v string) predicate.Series {
|
||||
return predicate.Series(sql.FieldLT(FieldPosterPath, v))
|
||||
}
|
||||
|
||||
// PosterPathLTE applies the LTE predicate on the "poster_path" field.
|
||||
func PosterPathLTE(v string) predicate.Series {
|
||||
return predicate.Series(sql.FieldLTE(FieldPosterPath, v))
|
||||
}
|
||||
|
||||
// PosterPathContains applies the Contains predicate on the "poster_path" field.
|
||||
func PosterPathContains(v string) predicate.Series {
|
||||
return predicate.Series(sql.FieldContains(FieldPosterPath, v))
|
||||
}
|
||||
|
||||
// PosterPathHasPrefix applies the HasPrefix predicate on the "poster_path" field.
|
||||
func PosterPathHasPrefix(v string) predicate.Series {
|
||||
return predicate.Series(sql.FieldHasPrefix(FieldPosterPath, v))
|
||||
}
|
||||
|
||||
// PosterPathHasSuffix applies the HasSuffix predicate on the "poster_path" field.
|
||||
func PosterPathHasSuffix(v string) predicate.Series {
|
||||
return predicate.Series(sql.FieldHasSuffix(FieldPosterPath, v))
|
||||
}
|
||||
|
||||
// PosterPathIsNil applies the IsNil predicate on the "poster_path" field.
|
||||
func PosterPathIsNil() predicate.Series {
|
||||
return predicate.Series(sql.FieldIsNull(FieldPosterPath))
|
||||
}
|
||||
|
||||
// PosterPathNotNil applies the NotNil predicate on the "poster_path" field.
|
||||
func PosterPathNotNil() predicate.Series {
|
||||
return predicate.Series(sql.FieldNotNull(FieldPosterPath))
|
||||
}
|
||||
|
||||
// PosterPathEqualFold applies the EqualFold predicate on the "poster_path" field.
|
||||
func PosterPathEqualFold(v string) predicate.Series {
|
||||
return predicate.Series(sql.FieldEqualFold(FieldPosterPath, v))
|
||||
}
|
||||
|
||||
// PosterPathContainsFold applies the ContainsFold predicate on the "poster_path" field.
|
||||
func PosterPathContainsFold(v string) predicate.Series {
|
||||
return predicate.Series(sql.FieldContainsFold(FieldPosterPath, v))
|
||||
}
|
||||
|
||||
// And groups predicates with the AND operator between them.
|
||||
func And(predicates ...predicate.Series) predicate.Series {
|
||||
return predicate.Series(sql.AndPredicates(predicates...))
|
||||
|
||||
@@ -31,6 +31,14 @@ func (sc *SeriesCreate) SetImdbID(s string) *SeriesCreate {
|
||||
return sc
|
||||
}
|
||||
|
||||
// SetNillableImdbID sets the "imdb_id" field if the given value is not nil.
|
||||
func (sc *SeriesCreate) SetNillableImdbID(s *string) *SeriesCreate {
|
||||
if s != nil {
|
||||
sc.SetImdbID(*s)
|
||||
}
|
||||
return sc
|
||||
}
|
||||
|
||||
// SetTitle sets the "title" field.
|
||||
func (sc *SeriesCreate) SetTitle(s string) *SeriesCreate {
|
||||
sc.mutation.SetTitle(s)
|
||||
@@ -55,6 +63,20 @@ func (sc *SeriesCreate) SetPath(s string) *SeriesCreate {
|
||||
return sc
|
||||
}
|
||||
|
||||
// SetPosterPath sets the "poster_path" field.
|
||||
func (sc *SeriesCreate) SetPosterPath(s string) *SeriesCreate {
|
||||
sc.mutation.SetPosterPath(s)
|
||||
return sc
|
||||
}
|
||||
|
||||
// SetNillablePosterPath sets the "poster_path" field if the given value is not nil.
|
||||
func (sc *SeriesCreate) SetNillablePosterPath(s *string) *SeriesCreate {
|
||||
if s != nil {
|
||||
sc.SetPosterPath(*s)
|
||||
}
|
||||
return sc
|
||||
}
|
||||
|
||||
// Mutation returns the SeriesMutation object of the builder.
|
||||
func (sc *SeriesCreate) Mutation() *SeriesMutation {
|
||||
return sc.mutation
|
||||
@@ -92,9 +114,6 @@ func (sc *SeriesCreate) check() error {
|
||||
if _, ok := sc.mutation.TmdbID(); !ok {
|
||||
return &ValidationError{Name: "tmdb_id", err: errors.New(`ent: missing required field "Series.tmdb_id"`)}
|
||||
}
|
||||
if _, ok := sc.mutation.ImdbID(); !ok {
|
||||
return &ValidationError{Name: "imdb_id", err: errors.New(`ent: missing required field "Series.imdb_id"`)}
|
||||
}
|
||||
if _, ok := sc.mutation.Title(); !ok {
|
||||
return &ValidationError{Name: "title", err: errors.New(`ent: missing required field "Series.title"`)}
|
||||
}
|
||||
@@ -157,6 +176,10 @@ func (sc *SeriesCreate) createSpec() (*Series, *sqlgraph.CreateSpec) {
|
||||
_spec.SetField(series.FieldPath, field.TypeString, value)
|
||||
_node.Path = value
|
||||
}
|
||||
if value, ok := sc.mutation.PosterPath(); ok {
|
||||
_spec.SetField(series.FieldPosterPath, field.TypeString, value)
|
||||
_node.PosterPath = value
|
||||
}
|
||||
return _node, _spec
|
||||
}
|
||||
|
||||
|
||||
@@ -62,6 +62,12 @@ func (su *SeriesUpdate) SetNillableImdbID(s *string) *SeriesUpdate {
|
||||
return su
|
||||
}
|
||||
|
||||
// ClearImdbID clears the value of the "imdb_id" field.
|
||||
func (su *SeriesUpdate) ClearImdbID() *SeriesUpdate {
|
||||
su.mutation.ClearImdbID()
|
||||
return su
|
||||
}
|
||||
|
||||
// SetTitle sets the "title" field.
|
||||
func (su *SeriesUpdate) SetTitle(s string) *SeriesUpdate {
|
||||
su.mutation.SetTitle(s)
|
||||
@@ -118,6 +124,26 @@ func (su *SeriesUpdate) SetNillablePath(s *string) *SeriesUpdate {
|
||||
return su
|
||||
}
|
||||
|
||||
// SetPosterPath sets the "poster_path" field.
|
||||
func (su *SeriesUpdate) SetPosterPath(s string) *SeriesUpdate {
|
||||
su.mutation.SetPosterPath(s)
|
||||
return su
|
||||
}
|
||||
|
||||
// SetNillablePosterPath sets the "poster_path" field if the given value is not nil.
|
||||
func (su *SeriesUpdate) SetNillablePosterPath(s *string) *SeriesUpdate {
|
||||
if s != nil {
|
||||
su.SetPosterPath(*s)
|
||||
}
|
||||
return su
|
||||
}
|
||||
|
||||
// ClearPosterPath clears the value of the "poster_path" field.
|
||||
func (su *SeriesUpdate) ClearPosterPath() *SeriesUpdate {
|
||||
su.mutation.ClearPosterPath()
|
||||
return su
|
||||
}
|
||||
|
||||
// Mutation returns the SeriesMutation object of the builder.
|
||||
func (su *SeriesUpdate) Mutation() *SeriesMutation {
|
||||
return su.mutation
|
||||
@@ -168,6 +194,9 @@ func (su *SeriesUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||
if value, ok := su.mutation.ImdbID(); ok {
|
||||
_spec.SetField(series.FieldImdbID, field.TypeString, value)
|
||||
}
|
||||
if su.mutation.ImdbIDCleared() {
|
||||
_spec.ClearField(series.FieldImdbID, field.TypeString)
|
||||
}
|
||||
if value, ok := su.mutation.Title(); ok {
|
||||
_spec.SetField(series.FieldTitle, field.TypeString, value)
|
||||
}
|
||||
@@ -180,6 +209,12 @@ func (su *SeriesUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||
if value, ok := su.mutation.Path(); ok {
|
||||
_spec.SetField(series.FieldPath, field.TypeString, value)
|
||||
}
|
||||
if value, ok := su.mutation.PosterPath(); ok {
|
||||
_spec.SetField(series.FieldPosterPath, field.TypeString, value)
|
||||
}
|
||||
if su.mutation.PosterPathCleared() {
|
||||
_spec.ClearField(series.FieldPosterPath, field.TypeString)
|
||||
}
|
||||
if n, err = sqlgraph.UpdateNodes(ctx, su.driver, _spec); err != nil {
|
||||
if _, ok := err.(*sqlgraph.NotFoundError); ok {
|
||||
err = &NotFoundError{series.Label}
|
||||
@@ -235,6 +270,12 @@ func (suo *SeriesUpdateOne) SetNillableImdbID(s *string) *SeriesUpdateOne {
|
||||
return suo
|
||||
}
|
||||
|
||||
// ClearImdbID clears the value of the "imdb_id" field.
|
||||
func (suo *SeriesUpdateOne) ClearImdbID() *SeriesUpdateOne {
|
||||
suo.mutation.ClearImdbID()
|
||||
return suo
|
||||
}
|
||||
|
||||
// SetTitle sets the "title" field.
|
||||
func (suo *SeriesUpdateOne) SetTitle(s string) *SeriesUpdateOne {
|
||||
suo.mutation.SetTitle(s)
|
||||
@@ -291,6 +332,26 @@ func (suo *SeriesUpdateOne) SetNillablePath(s *string) *SeriesUpdateOne {
|
||||
return suo
|
||||
}
|
||||
|
||||
// SetPosterPath sets the "poster_path" field.
|
||||
func (suo *SeriesUpdateOne) SetPosterPath(s string) *SeriesUpdateOne {
|
||||
suo.mutation.SetPosterPath(s)
|
||||
return suo
|
||||
}
|
||||
|
||||
// SetNillablePosterPath sets the "poster_path" field if the given value is not nil.
|
||||
func (suo *SeriesUpdateOne) SetNillablePosterPath(s *string) *SeriesUpdateOne {
|
||||
if s != nil {
|
||||
suo.SetPosterPath(*s)
|
||||
}
|
||||
return suo
|
||||
}
|
||||
|
||||
// ClearPosterPath clears the value of the "poster_path" field.
|
||||
func (suo *SeriesUpdateOne) ClearPosterPath() *SeriesUpdateOne {
|
||||
suo.mutation.ClearPosterPath()
|
||||
return suo
|
||||
}
|
||||
|
||||
// Mutation returns the SeriesMutation object of the builder.
|
||||
func (suo *SeriesUpdateOne) Mutation() *SeriesMutation {
|
||||
return suo.mutation
|
||||
@@ -371,6 +432,9 @@ func (suo *SeriesUpdateOne) sqlSave(ctx context.Context) (_node *Series, err err
|
||||
if value, ok := suo.mutation.ImdbID(); ok {
|
||||
_spec.SetField(series.FieldImdbID, field.TypeString, value)
|
||||
}
|
||||
if suo.mutation.ImdbIDCleared() {
|
||||
_spec.ClearField(series.FieldImdbID, field.TypeString)
|
||||
}
|
||||
if value, ok := suo.mutation.Title(); ok {
|
||||
_spec.SetField(series.FieldTitle, field.TypeString, value)
|
||||
}
|
||||
@@ -383,6 +447,12 @@ func (suo *SeriesUpdateOne) sqlSave(ctx context.Context) (_node *Series, err err
|
||||
if value, ok := suo.mutation.Path(); ok {
|
||||
_spec.SetField(series.FieldPath, field.TypeString, value)
|
||||
}
|
||||
if value, ok := suo.mutation.PosterPath(); ok {
|
||||
_spec.SetField(series.FieldPosterPath, field.TypeString, value)
|
||||
}
|
||||
if suo.mutation.PosterPathCleared() {
|
||||
_spec.ClearField(series.FieldPosterPath, field.TypeString)
|
||||
}
|
||||
_node = &Series{config: suo.config}
|
||||
_spec.Assign = _node.assignValues
|
||||
_spec.ScanValues = _node.scanValues
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package tmdb
|
||||
|
||||
import (
|
||||
"polaris/log"
|
||||
|
||||
tmdb "github.com/cyruzin/golang-tmdb"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
@@ -23,6 +25,7 @@ func NewClient(apiKey string) (*Client, error) {
|
||||
}
|
||||
|
||||
func (c *Client) GetTvDetails(id int, language string) (*tmdb.TVDetails, error) {
|
||||
log.Infof("tv id %d, language %s", id, language)
|
||||
language = wrapLanguage(language)
|
||||
d, err := c.tmdbClient.GetTVDetails(id, withLangOption(language))
|
||||
return d, err
|
||||
|
||||
@@ -12,6 +12,7 @@ func HttpHandler(f func(*gin.Context) (interface{}, error)) gin.HandlerFunc {
|
||||
|
||||
r, err := f(ctx)
|
||||
if err != nil {
|
||||
log.Errorf("url %v return error: %v", ctx.Request.URL, err)
|
||||
ctx.JSON(200, Response{
|
||||
Code: 1,
|
||||
Message: fmt.Sprintf("%v", err),
|
||||
|
||||
@@ -31,17 +31,19 @@ type addWatchlistIn struct {
|
||||
|
||||
func (s *Server) AddWatchlist(c *gin.Context) (interface{}, error) {
|
||||
var in addWatchlistIn
|
||||
if err := c.ShouldBindQuery(&in); err != nil {
|
||||
if err := c.ShouldBindJSON(&in); err != nil {
|
||||
return nil, errors.Wrap(err, "bind query")
|
||||
}
|
||||
detail, err := s.MustTMDB().GetTvDetails(in.ID, s.language)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "get tv detail")
|
||||
}
|
||||
log.Infof("find detail for tv id %d: %v", in.ID, detail)
|
||||
|
||||
if err := s.db.AddWatchlist(in.RootFolder, detail); err != nil {
|
||||
return nil, errors.Wrap(err, "add to list")
|
||||
}
|
||||
log.Infof("save watchlist success: %s", detail.Name)
|
||||
|
||||
for _, season := range detail.Seasons {
|
||||
seasonId := season.SeasonNumber
|
||||
|
||||
@@ -2,6 +2,7 @@ class APIs {
|
||||
static const _baseUrl = "http://127.0.0.1:8080";
|
||||
static const searchUrl = "$_baseUrl/api/v1/tv/search";
|
||||
static const settingsUrl = "$_baseUrl/api/v1/setting/do";
|
||||
static const watchlistUrl = "$_baseUrl/api/v1/tv/watchlist";
|
||||
|
||||
static const tmdbImgBaseUrl = "https://image.tmdb.org/t/p/w500/";
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ class _SearchPageState extends State<SearchPage> {
|
||||
Widget build(BuildContext context) {
|
||||
var cards = List<Widget>.empty(growable: true);
|
||||
for (final item in list) {
|
||||
var m = item as Map<String, dynamic>;
|
||||
var m = SearchResult.fromJson(item);
|
||||
cards.add(Card(
|
||||
margin: const EdgeInsets.all(4),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
@@ -50,7 +50,7 @@ class _SearchPageState extends State<SearchPage> {
|
||||
//splashColor: Colors.blue.withAlpha(30),
|
||||
onTap: () {
|
||||
//showDialog(context: context, builder: builder)
|
||||
debugPrint('Card tapped.');
|
||||
_showSubmitDialog(context, m);
|
||||
},
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
@@ -59,7 +59,7 @@ class _SearchPageState extends State<SearchPage> {
|
||||
width: 150,
|
||||
height: 200,
|
||||
child: Image.network(
|
||||
APIs.tmdbImgBaseUrl + m["poster_path"],
|
||||
APIs.tmdbImgBaseUrl + m.posterPath!,
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
),
|
||||
@@ -69,12 +69,12 @@ class _SearchPageState extends State<SearchPage> {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
m["name"],
|
||||
m.name!,
|
||||
style: const TextStyle(
|
||||
fontSize: 14, fontWeight: FontWeight.bold),
|
||||
),
|
||||
const Text(""),
|
||||
Text(m["overview"])
|
||||
Text(m.overview!)
|
||||
],
|
||||
),
|
||||
)
|
||||
@@ -83,25 +83,64 @@ class _SearchPageState extends State<SearchPage> {
|
||||
)));
|
||||
}
|
||||
|
||||
return Expanded(
|
||||
child: Column(
|
||||
children: [
|
||||
TextField(
|
||||
autofocus: true,
|
||||
onSubmitted: (value) => _queryResults(context,value),
|
||||
decoration: const InputDecoration(
|
||||
labelText: "搜索",
|
||||
hintText: "搜索剧集名称",
|
||||
prefixIcon: Icon(Icons.search)),
|
||||
),
|
||||
Expanded(
|
||||
child: ListView(
|
||||
children: cards,
|
||||
))
|
||||
],
|
||||
),
|
||||
return Column(
|
||||
children: [
|
||||
TextField(
|
||||
autofocus: true,
|
||||
onSubmitted: (value) => _queryResults(context, value),
|
||||
decoration: const InputDecoration(
|
||||
labelText: "搜索",
|
||||
hintText: "搜索剧集名称",
|
||||
prefixIcon: Icon(Icons.search)),
|
||||
),
|
||||
Expanded(
|
||||
child: ListView(
|
||||
children: cards,
|
||||
))
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _showSubmitDialog(BuildContext context, SearchResult item) {
|
||||
return showDialog<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertDialog(
|
||||
title: const Text('添加剧集'),
|
||||
content: Text("是否添加剧集: ${item.name}"),
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
textStyle: Theme.of(context).textTheme.labelLarge,
|
||||
),
|
||||
child: const Text('取消'),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
style: TextButton.styleFrom(
|
||||
textStyle: Theme.of(context).textTheme.labelLarge,
|
||||
),
|
||||
child: const Text('确定'),
|
||||
onPressed: () {
|
||||
_submit2Watchlist(context, item.id!);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void _submit2Watchlist(BuildContext context, int id) async {
|
||||
var resp = await Dio()
|
||||
.post(APIs.watchlistUrl, data: {"id": id, "folder": "/downloads"});
|
||||
var sp = ServerResponse.fromJson(resp.data);
|
||||
if (sp.code != 0 && context.mounted) {
|
||||
Utils.showAlertDialog(context, sp.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SearchBarApp extends StatefulWidget {
|
||||
@@ -142,3 +181,50 @@ class _SearchBarAppState extends State<SearchBarApp> {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class SearchResult {
|
||||
String? originalName;
|
||||
int? id;
|
||||
String? name;
|
||||
int? voteCount;
|
||||
double? voteAverage;
|
||||
String? posterPath;
|
||||
String? firstAirDate;
|
||||
double? popularity;
|
||||
List<int>? genreIds;
|
||||
String? originalLanguage;
|
||||
String? backdropPath;
|
||||
String? overview;
|
||||
List<String>? originCountry;
|
||||
|
||||
SearchResult(
|
||||
{this.originalName,
|
||||
this.id,
|
||||
this.name,
|
||||
this.voteCount,
|
||||
this.voteAverage,
|
||||
this.posterPath,
|
||||
this.firstAirDate,
|
||||
this.popularity,
|
||||
this.genreIds,
|
||||
this.originalLanguage,
|
||||
this.backdropPath,
|
||||
this.overview,
|
||||
this.originCountry});
|
||||
|
||||
SearchResult.fromJson(Map<String, dynamic> json) {
|
||||
originalName = json['original_name'];
|
||||
id = json['id'];
|
||||
name = json['name'];
|
||||
voteCount = json['vote_count'];
|
||||
voteAverage = json['vote_average'];
|
||||
posterPath = json['poster_path'];
|
||||
firstAirDate = json['first_air_date'];
|
||||
popularity = json['popularity'];
|
||||
genreIds = json['genre_ids'].cast<int>();
|
||||
originalLanguage = json['original_language'];
|
||||
backdropPath = json['backdrop_path'];
|
||||
overview = json['overview'];
|
||||
originCountry = json['origin_country'].cast<String>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ import 'package:ui/utils.dart';
|
||||
|
||||
class SystemSettingsPage extends StatefulWidget {
|
||||
static const route = "/systemsettings";
|
||||
|
||||
const SystemSettingsPage({super.key});
|
||||
@override
|
||||
State<StatefulWidget> createState() {
|
||||
return _SystemSettingsPageState();
|
||||
@@ -19,8 +21,7 @@ class _SystemSettingsPageState extends State<SystemSettingsPage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
_handleRefresh();
|
||||
return Expanded(
|
||||
child: Container(
|
||||
return Container(
|
||||
padding: const EdgeInsets.fromLTRB(40, 10, 40, 0),
|
||||
child: RefreshIndicator(
|
||||
onRefresh: _handleRefresh,
|
||||
@@ -63,7 +64,7 @@ class _SystemSettingsPageState extends State<SystemSettingsPage> {
|
||||
],
|
||||
),
|
||||
)),
|
||||
));
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _handleRefresh() async {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:ui/APIs.dart';
|
||||
import 'package:ui/server_response.dart';
|
||||
|
||||
class WelcomePage extends StatefulWidget {
|
||||
const WelcomePage({super.key});
|
||||
@@ -16,57 +18,85 @@ class _WeclomePageState extends State<WelcomePage> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var cards = List<Widget>.empty(growable: true);
|
||||
for (final item in favList) {
|
||||
var m = item as Map<String, dynamic>;
|
||||
cards.add(Card(
|
||||
margin: const EdgeInsets.all(4),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
child: InkWell(
|
||||
//splashColor: Colors.blue.withAlpha(30),
|
||||
onTap: () {
|
||||
//showDialog(context: context, builder: builder)
|
||||
debugPrint('Card tapped.');
|
||||
},
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: SizedBox(
|
||||
width: 150,
|
||||
height: 200,
|
||||
child: Image.network(
|
||||
APIs.tmdbImgBaseUrl + m["poster_path"],
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
m["name"],
|
||||
style: const TextStyle(
|
||||
fontSize: 14, fontWeight: FontWeight.bold),
|
||||
_onRefresh();
|
||||
return GridView.builder(
|
||||
itemCount: favList.length,
|
||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 4),
|
||||
itemBuilder: (context, i) {
|
||||
var item = TvSeries.fromJson(favList[i]);
|
||||
return Container(
|
||||
child: Card(
|
||||
margin: const EdgeInsets.all(4),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
child: InkWell(
|
||||
//splashColor: Colors.blue.withAlpha(30),
|
||||
onTap: () {
|
||||
//showDialog(context: context, builder: builder)
|
||||
},
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: SizedBox(
|
||||
width: 300,
|
||||
height: 600,
|
||||
child: Image.network(
|
||||
APIs.tmdbImgBaseUrl + item.posterPath!,
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: Text(
|
||||
item.title!,
|
||||
style: const TextStyle(
|
||||
fontSize: 14, fontWeight: FontWeight.bold),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
const Text(""),
|
||||
Text(m["overview"])
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
)));
|
||||
}
|
||||
|
||||
return Expanded(
|
||||
child: RefreshIndicator(
|
||||
onRefresh: _onRefresh,
|
||||
child: Expanded(
|
||||
child: ListView(
|
||||
children: cards,
|
||||
))));
|
||||
)),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _onRefresh() async {}
|
||||
Future<void> _onRefresh() async {
|
||||
if (favList.isNotEmpty) {
|
||||
return;
|
||||
}
|
||||
var resp = await Dio().get(APIs.watchlistUrl);
|
||||
var sp = ServerResponse.fromJson(resp.data);
|
||||
setState(() {
|
||||
favList = sp.data as List;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class TvSeries {
|
||||
int? id;
|
||||
int? tmdbId;
|
||||
String? title;
|
||||
String? originalName;
|
||||
String? overview;
|
||||
String? path;
|
||||
String? posterPath;
|
||||
|
||||
TvSeries(
|
||||
{this.id,
|
||||
this.tmdbId,
|
||||
this.title,
|
||||
this.originalName,
|
||||
this.overview,
|
||||
this.path,
|
||||
this.posterPath});
|
||||
|
||||
TvSeries.fromJson(Map<String, dynamic> json) {
|
||||
id = json['id'];
|
||||
tmdbId = json['tmdb_id'];
|
||||
title = json['title'];
|
||||
originalName = json['original_name'];
|
||||
overview = json['overview'];
|
||||
path = json['path'];
|
||||
posterPath = json["poster_path"];
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user