feat: download tmdb img & change name_cn

This commit is contained in:
Simon Ding
2024-07-14 11:59:06 +08:00
parent 294ab45218
commit 32787c5ed3
21 changed files with 197 additions and 192 deletions

1
.gitignore vendored
View File

@@ -11,6 +11,7 @@ config.yml
.idea/
.DS_Store
*.db
data/
ui/node_modules/
ui/dist/

View File

@@ -16,6 +16,13 @@ const (
const (
IndexerTorznabImpl = "torznab"
DataPath = "./data"
ImgPath = DataPath + "/img"
)
const (
LanguageEN = "en-US"
LanguageCN = "zh-CN"
)
type ResolutionType string

View File

@@ -28,8 +28,8 @@ type Client struct {
}
func Open() (*Client, error) {
os.Mkdir("./db", 0666)
client, err := ent.Open(dialect.SQLite, "file:./db/polaris.db?cache=shared&_fk=1")
os.Mkdir(DataPath, 0777)
client, err := ent.Open(dialect.SQLite, fmt.Sprintf("file:%v/polaris.db?cache=shared&_fk=1", DataPath))
if err != nil {
return nil, errors.Wrap(err, "failed opening connection to sqlite")
}
@@ -72,7 +72,7 @@ func (c *Client) GetLanguage() string {
return lang
}
func (c *Client) AddWatchlist(storageId int, nameEn string, detail *tmdb.TVDetails, episodes []int, res ResolutionType) (*ent.Series, error) {
func (c *Client) AddWatchlist(storageId int, nameCn, nameEn string, detail *tmdb.TVDetails, episodes []int, res ResolutionType) (*ent.Series, error) {
count := c.ent.Series.Query().Where(series.TmdbID(int(detail.ID))).CountX(context.Background())
if count > 0 {
return nil, fmt.Errorf("tv series %s already in watchlist", detail.Name)
@@ -92,7 +92,7 @@ func (c *Client) AddWatchlist(storageId int, nameEn string, detail *tmdb.TVDetai
SetTmdbID(int(detail.ID)).
SetStorageID(storageId).
SetOverview(detail.Overview).
SetName(detail.Name).
SetNameCn(nameCn).
SetNameEn(nameEn).
SetOriginalName(detail.OriginalName).
SetPosterPath(detail.PosterPath).
@@ -320,9 +320,8 @@ func (c *Client) SetDefaultStorageByName(name string) error {
return err
}
func (c *Client) SaveHistoryRecord(h ent.History) (*ent.History,error) {
return c.ent.History.Create().SetSeriesID(h.SeriesID).SetEpisodeID(h.EpisodeID).SetDate(time.Now()).
func (c *Client) SaveHistoryRecord(h ent.History) (*ent.History, error) {
return c.ent.History.Create().SetSeriesID(h.SeriesID).SetEpisodeID(h.EpisodeID).SetDate(time.Now()).
SetCompleted(h.Completed).SetTargetDir(h.TargetDir).SetSourceTitle(h.SourceTitle).SetSaved(h.Saved).Save(context.TODO())
}
@@ -346,22 +345,19 @@ func (c *Client) GetRunningHistories() ent.Histories {
return h
}
func (c *Client) GetHistory(id int) *ent.History {
return c.ent.History.Query().Where(history.ID(id)).FirstX(context.TODO())
}
func (c *Client) DeleteHistory(id int) error {
_, err := c.ent.History.Delete().Where(history.ID(id)).Exec(context.Background())
return err
}
func (c *Client) GetDownloadDir() string {
r, err := c.ent.Settings.Query().Where(settings.Key(SettingDownloadDir)).First(context.TODO())
if err != nil {
return "/downloads"
}
return r.Value
}
}

View File

@@ -90,8 +90,8 @@ var (
{Name: "id", Type: field.TypeInt, Increment: true},
{Name: "tmdb_id", Type: field.TypeInt},
{Name: "imdb_id", Type: field.TypeString, Nullable: true},
{Name: "name", Type: field.TypeString},
{Name: "name_en", Type: field.TypeString, Nullable: true},
{Name: "name_cn", Type: field.TypeString},
{Name: "name_en", Type: field.TypeString},
{Name: "original_name", Type: field.TypeString},
{Name: "overview", Type: field.TypeString},
{Name: "poster_path", Type: field.TypeString, Nullable: true},

View File

@@ -2974,7 +2974,7 @@ type SeriesMutation struct {
tmdb_id *int
addtmdb_id *int
imdb_id *string
name *string
name_cn *string
name_en *string
original_name *string
overview *string
@@ -3196,40 +3196,40 @@ func (m *SeriesMutation) ResetImdbID() {
delete(m.clearedFields, series.FieldImdbID)
}
// SetName sets the "name" field.
func (m *SeriesMutation) SetName(s string) {
m.name = &s
// SetNameCn sets the "name_cn" field.
func (m *SeriesMutation) SetNameCn(s string) {
m.name_cn = &s
}
// Name returns the value of the "name" field in the mutation.
func (m *SeriesMutation) Name() (r string, exists bool) {
v := m.name
// NameCn returns the value of the "name_cn" field in the mutation.
func (m *SeriesMutation) NameCn() (r string, exists bool) {
v := m.name_cn
if v == nil {
return
}
return *v, true
}
// OldName returns the old "name" field's value of the Series entity.
// OldNameCn returns the old "name_cn" 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) OldName(ctx context.Context) (v string, err error) {
func (m *SeriesMutation) OldNameCn(ctx context.Context) (v string, err error) {
if !m.op.Is(OpUpdateOne) {
return v, errors.New("OldName is only allowed on UpdateOne operations")
return v, errors.New("OldNameCn 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")
return v, errors.New("OldNameCn 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 v, fmt.Errorf("querying old value for OldNameCn: %w", err)
}
return oldValue.Name, nil
return oldValue.NameCn, nil
}
// ResetName resets all changes to the "name" field.
func (m *SeriesMutation) ResetName() {
m.name = nil
// ResetNameCn resets all changes to the "name_cn" field.
func (m *SeriesMutation) ResetNameCn() {
m.name_cn = nil
}
// SetNameEn sets the "name_en" field.
@@ -3263,22 +3263,9 @@ func (m *SeriesMutation) OldNameEn(ctx context.Context) (v string, err error) {
return oldValue.NameEn, nil
}
// ClearNameEn clears the value of the "name_en" field.
func (m *SeriesMutation) ClearNameEn() {
m.name_en = nil
m.clearedFields[series.FieldNameEn] = struct{}{}
}
// NameEnCleared returns if the "name_en" field was cleared in this mutation.
func (m *SeriesMutation) NameEnCleared() bool {
_, ok := m.clearedFields[series.FieldNameEn]
return ok
}
// ResetNameEn resets all changes to the "name_en" field.
func (m *SeriesMutation) ResetNameEn() {
m.name_en = nil
delete(m.clearedFields, series.FieldNameEn)
}
// SetOriginalName sets the "original_name" field.
@@ -3675,8 +3662,8 @@ func (m *SeriesMutation) Fields() []string {
if m.imdb_id != nil {
fields = append(fields, series.FieldImdbID)
}
if m.name != nil {
fields = append(fields, series.FieldName)
if m.name_cn != nil {
fields = append(fields, series.FieldNameCn)
}
if m.name_en != nil {
fields = append(fields, series.FieldNameEn)
@@ -3714,8 +3701,8 @@ func (m *SeriesMutation) Field(name string) (ent.Value, bool) {
return m.TmdbID()
case series.FieldImdbID:
return m.ImdbID()
case series.FieldName:
return m.Name()
case series.FieldNameCn:
return m.NameCn()
case series.FieldNameEn:
return m.NameEn()
case series.FieldOriginalName:
@@ -3745,8 +3732,8 @@ func (m *SeriesMutation) OldField(ctx context.Context, name string) (ent.Value,
return m.OldTmdbID(ctx)
case series.FieldImdbID:
return m.OldImdbID(ctx)
case series.FieldName:
return m.OldName(ctx)
case series.FieldNameCn:
return m.OldNameCn(ctx)
case series.FieldNameEn:
return m.OldNameEn(ctx)
case series.FieldOriginalName:
@@ -3786,12 +3773,12 @@ func (m *SeriesMutation) SetField(name string, value ent.Value) error {
}
m.SetImdbID(v)
return nil
case series.FieldName:
case series.FieldNameCn:
v, ok := value.(string)
if !ok {
return fmt.Errorf("unexpected type %T for field %s", value, name)
}
m.SetName(v)
m.SetNameCn(v)
return nil
case series.FieldNameEn:
v, ok := value.(string)
@@ -3909,9 +3896,6 @@ func (m *SeriesMutation) ClearedFields() []string {
if m.FieldCleared(series.FieldImdbID) {
fields = append(fields, series.FieldImdbID)
}
if m.FieldCleared(series.FieldNameEn) {
fields = append(fields, series.FieldNameEn)
}
if m.FieldCleared(series.FieldPosterPath) {
fields = append(fields, series.FieldPosterPath)
}
@@ -3935,9 +3919,6 @@ func (m *SeriesMutation) ClearField(name string) error {
case series.FieldImdbID:
m.ClearImdbID()
return nil
case series.FieldNameEn:
m.ClearNameEn()
return nil
case series.FieldPosterPath:
m.ClearPosterPath()
return nil
@@ -3958,8 +3939,8 @@ func (m *SeriesMutation) ResetField(name string) error {
case series.FieldImdbID:
m.ResetImdbID()
return nil
case series.FieldName:
m.ResetName()
case series.FieldNameCn:
m.ResetNameCn()
return nil
case series.FieldNameEn:
m.ResetNameEn()

View File

@@ -18,8 +18,8 @@ func (Series) Fields() []ent.Field {
return []ent.Field{
field.Int("tmdb_id"),
field.String("imdb_id").Optional(),
field.String("name"),
field.String("name_en").Optional(),
field.String("name_cn"),
field.String("name_en"),
field.String("original_name"),
field.String("overview"),
field.String("poster_path").Optional(),

View File

@@ -21,8 +21,8 @@ type Series struct {
TmdbID int `json:"tmdb_id,omitempty"`
// ImdbID holds the value of the "imdb_id" field.
ImdbID string `json:"imdb_id,omitempty"`
// Name holds the value of the "name" field.
Name string `json:"name,omitempty"`
// NameCn holds the value of the "name_cn" field.
NameCn string `json:"name_cn,omitempty"`
// NameEn holds the value of the "name_en" field.
NameEn string `json:"name_en,omitempty"`
// OriginalName holds the value of the "original_name" field.
@@ -70,7 +70,7 @@ func (*Series) scanValues(columns []string) ([]any, error) {
switch columns[i] {
case series.FieldID, series.FieldTmdbID, series.FieldStorageID:
values[i] = new(sql.NullInt64)
case series.FieldImdbID, series.FieldName, series.FieldNameEn, series.FieldOriginalName, series.FieldOverview, series.FieldPosterPath, series.FieldAirDate, series.FieldResolution:
case series.FieldImdbID, series.FieldNameCn, series.FieldNameEn, series.FieldOriginalName, series.FieldOverview, series.FieldPosterPath, series.FieldAirDate, series.FieldResolution:
values[i] = new(sql.NullString)
case series.FieldCreatedAt:
values[i] = new(sql.NullTime)
@@ -107,11 +107,11 @@ func (s *Series) assignValues(columns []string, values []any) error {
} else if value.Valid {
s.ImdbID = value.String
}
case series.FieldName:
case series.FieldNameCn:
if value, ok := values[i].(*sql.NullString); !ok {
return fmt.Errorf("unexpected type %T for field name", values[i])
return fmt.Errorf("unexpected type %T for field name_cn", values[i])
} else if value.Valid {
s.Name = value.String
s.NameCn = value.String
}
case series.FieldNameEn:
if value, ok := values[i].(*sql.NullString); !ok {
@@ -208,8 +208,8 @@ func (s *Series) String() string {
builder.WriteString("imdb_id=")
builder.WriteString(s.ImdbID)
builder.WriteString(", ")
builder.WriteString("name=")
builder.WriteString(s.Name)
builder.WriteString("name_cn=")
builder.WriteString(s.NameCn)
builder.WriteString(", ")
builder.WriteString("name_en=")
builder.WriteString(s.NameEn)

View File

@@ -18,8 +18,8 @@ const (
FieldTmdbID = "tmdb_id"
// FieldImdbID holds the string denoting the imdb_id field in the database.
FieldImdbID = "imdb_id"
// FieldName holds the string denoting the name field in the database.
FieldName = "name"
// FieldNameCn holds the string denoting the name_cn field in the database.
FieldNameCn = "name_cn"
// FieldNameEn holds the string denoting the name_en field in the database.
FieldNameEn = "name_en"
// FieldOriginalName holds the string denoting the original_name field in the database.
@@ -54,7 +54,7 @@ var Columns = []string{
FieldID,
FieldTmdbID,
FieldImdbID,
FieldName,
FieldNameCn,
FieldNameEn,
FieldOriginalName,
FieldOverview,
@@ -102,9 +102,9 @@ func ByImdbID(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldImdbID, opts...).ToFunc()
}
// ByName orders the results by the name field.
func ByName(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldName, opts...).ToFunc()
// ByNameCn orders the results by the name_cn field.
func ByNameCn(opts ...sql.OrderTermOption) OrderOption {
return sql.OrderByField(FieldNameCn, opts...).ToFunc()
}
// ByNameEn orders the results by the name_en field.

View File

@@ -65,9 +65,9 @@ func ImdbID(v string) predicate.Series {
return predicate.Series(sql.FieldEQ(FieldImdbID, v))
}
// Name applies equality check predicate on the "name" field. It's identical to NameEQ.
func Name(v string) predicate.Series {
return predicate.Series(sql.FieldEQ(FieldName, v))
// NameCn applies equality check predicate on the "name_cn" field. It's identical to NameCnEQ.
func NameCn(v string) predicate.Series {
return predicate.Series(sql.FieldEQ(FieldNameCn, v))
}
// NameEn applies equality check predicate on the "name_en" field. It's identical to NameEnEQ.
@@ -225,69 +225,69 @@ func ImdbIDContainsFold(v string) predicate.Series {
return predicate.Series(sql.FieldContainsFold(FieldImdbID, v))
}
// NameEQ applies the EQ predicate on the "name" field.
func NameEQ(v string) predicate.Series {
return predicate.Series(sql.FieldEQ(FieldName, v))
// NameCnEQ applies the EQ predicate on the "name_cn" field.
func NameCnEQ(v string) predicate.Series {
return predicate.Series(sql.FieldEQ(FieldNameCn, v))
}
// NameNEQ applies the NEQ predicate on the "name" field.
func NameNEQ(v string) predicate.Series {
return predicate.Series(sql.FieldNEQ(FieldName, v))
// NameCnNEQ applies the NEQ predicate on the "name_cn" field.
func NameCnNEQ(v string) predicate.Series {
return predicate.Series(sql.FieldNEQ(FieldNameCn, v))
}
// NameIn applies the In predicate on the "name" field.
func NameIn(vs ...string) predicate.Series {
return predicate.Series(sql.FieldIn(FieldName, vs...))
// NameCnIn applies the In predicate on the "name_cn" field.
func NameCnIn(vs ...string) predicate.Series {
return predicate.Series(sql.FieldIn(FieldNameCn, vs...))
}
// NameNotIn applies the NotIn predicate on the "name" field.
func NameNotIn(vs ...string) predicate.Series {
return predicate.Series(sql.FieldNotIn(FieldName, vs...))
// NameCnNotIn applies the NotIn predicate on the "name_cn" field.
func NameCnNotIn(vs ...string) predicate.Series {
return predicate.Series(sql.FieldNotIn(FieldNameCn, vs...))
}
// NameGT applies the GT predicate on the "name" field.
func NameGT(v string) predicate.Series {
return predicate.Series(sql.FieldGT(FieldName, v))
// NameCnGT applies the GT predicate on the "name_cn" field.
func NameCnGT(v string) predicate.Series {
return predicate.Series(sql.FieldGT(FieldNameCn, v))
}
// NameGTE applies the GTE predicate on the "name" field.
func NameGTE(v string) predicate.Series {
return predicate.Series(sql.FieldGTE(FieldName, v))
// NameCnGTE applies the GTE predicate on the "name_cn" field.
func NameCnGTE(v string) predicate.Series {
return predicate.Series(sql.FieldGTE(FieldNameCn, v))
}
// NameLT applies the LT predicate on the "name" field.
func NameLT(v string) predicate.Series {
return predicate.Series(sql.FieldLT(FieldName, v))
// NameCnLT applies the LT predicate on the "name_cn" field.
func NameCnLT(v string) predicate.Series {
return predicate.Series(sql.FieldLT(FieldNameCn, v))
}
// NameLTE applies the LTE predicate on the "name" field.
func NameLTE(v string) predicate.Series {
return predicate.Series(sql.FieldLTE(FieldName, v))
// NameCnLTE applies the LTE predicate on the "name_cn" field.
func NameCnLTE(v string) predicate.Series {
return predicate.Series(sql.FieldLTE(FieldNameCn, v))
}
// NameContains applies the Contains predicate on the "name" field.
func NameContains(v string) predicate.Series {
return predicate.Series(sql.FieldContains(FieldName, v))
// NameCnContains applies the Contains predicate on the "name_cn" field.
func NameCnContains(v string) predicate.Series {
return predicate.Series(sql.FieldContains(FieldNameCn, v))
}
// NameHasPrefix applies the HasPrefix predicate on the "name" field.
func NameHasPrefix(v string) predicate.Series {
return predicate.Series(sql.FieldHasPrefix(FieldName, v))
// NameCnHasPrefix applies the HasPrefix predicate on the "name_cn" field.
func NameCnHasPrefix(v string) predicate.Series {
return predicate.Series(sql.FieldHasPrefix(FieldNameCn, v))
}
// NameHasSuffix applies the HasSuffix predicate on the "name" field.
func NameHasSuffix(v string) predicate.Series {
return predicate.Series(sql.FieldHasSuffix(FieldName, v))
// NameCnHasSuffix applies the HasSuffix predicate on the "name_cn" field.
func NameCnHasSuffix(v string) predicate.Series {
return predicate.Series(sql.FieldHasSuffix(FieldNameCn, v))
}
// NameEqualFold applies the EqualFold predicate on the "name" field.
func NameEqualFold(v string) predicate.Series {
return predicate.Series(sql.FieldEqualFold(FieldName, v))
// NameCnEqualFold applies the EqualFold predicate on the "name_cn" field.
func NameCnEqualFold(v string) predicate.Series {
return predicate.Series(sql.FieldEqualFold(FieldNameCn, v))
}
// NameContainsFold applies the ContainsFold predicate on the "name" field.
func NameContainsFold(v string) predicate.Series {
return predicate.Series(sql.FieldContainsFold(FieldName, v))
// NameCnContainsFold applies the ContainsFold predicate on the "name_cn" field.
func NameCnContainsFold(v string) predicate.Series {
return predicate.Series(sql.FieldContainsFold(FieldNameCn, v))
}
// NameEnEQ applies the EQ predicate on the "name_en" field.
@@ -345,16 +345,6 @@ func NameEnHasSuffix(v string) predicate.Series {
return predicate.Series(sql.FieldHasSuffix(FieldNameEn, v))
}
// NameEnIsNil applies the IsNil predicate on the "name_en" field.
func NameEnIsNil() predicate.Series {
return predicate.Series(sql.FieldIsNull(FieldNameEn))
}
// NameEnNotNil applies the NotNil predicate on the "name_en" field.
func NameEnNotNil() predicate.Series {
return predicate.Series(sql.FieldNotNull(FieldNameEn))
}
// NameEnEqualFold applies the EqualFold predicate on the "name_en" field.
func NameEnEqualFold(v string) predicate.Series {
return predicate.Series(sql.FieldEqualFold(FieldNameEn, v))

View File

@@ -41,9 +41,9 @@ func (sc *SeriesCreate) SetNillableImdbID(s *string) *SeriesCreate {
return sc
}
// SetName sets the "name" field.
func (sc *SeriesCreate) SetName(s string) *SeriesCreate {
sc.mutation.SetName(s)
// SetNameCn sets the "name_cn" field.
func (sc *SeriesCreate) SetNameCn(s string) *SeriesCreate {
sc.mutation.SetNameCn(s)
return sc
}
@@ -53,14 +53,6 @@ func (sc *SeriesCreate) SetNameEn(s string) *SeriesCreate {
return sc
}
// SetNillableNameEn sets the "name_en" field if the given value is not nil.
func (sc *SeriesCreate) SetNillableNameEn(s *string) *SeriesCreate {
if s != nil {
sc.SetNameEn(*s)
}
return sc
}
// SetOriginalName sets the "original_name" field.
func (sc *SeriesCreate) SetOriginalName(s string) *SeriesCreate {
sc.mutation.SetOriginalName(s)
@@ -212,8 +204,11 @@ 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.Name(); !ok {
return &ValidationError{Name: "name", err: errors.New(`ent: missing required field "Series.name"`)}
if _, ok := sc.mutation.NameCn(); !ok {
return &ValidationError{Name: "name_cn", err: errors.New(`ent: missing required field "Series.name_cn"`)}
}
if _, ok := sc.mutation.NameEn(); !ok {
return &ValidationError{Name: "name_en", err: errors.New(`ent: missing required field "Series.name_en"`)}
}
if _, ok := sc.mutation.OriginalName(); !ok {
return &ValidationError{Name: "original_name", err: errors.New(`ent: missing required field "Series.original_name"`)}
@@ -264,9 +259,9 @@ func (sc *SeriesCreate) createSpec() (*Series, *sqlgraph.CreateSpec) {
_spec.SetField(series.FieldImdbID, field.TypeString, value)
_node.ImdbID = value
}
if value, ok := sc.mutation.Name(); ok {
_spec.SetField(series.FieldName, field.TypeString, value)
_node.Name = value
if value, ok := sc.mutation.NameCn(); ok {
_spec.SetField(series.FieldNameCn, field.TypeString, value)
_node.NameCn = value
}
if value, ok := sc.mutation.NameEn(); ok {
_spec.SetField(series.FieldNameEn, field.TypeString, value)

View File

@@ -70,16 +70,16 @@ func (su *SeriesUpdate) ClearImdbID() *SeriesUpdate {
return su
}
// SetName sets the "name" field.
func (su *SeriesUpdate) SetName(s string) *SeriesUpdate {
su.mutation.SetName(s)
// SetNameCn sets the "name_cn" field.
func (su *SeriesUpdate) SetNameCn(s string) *SeriesUpdate {
su.mutation.SetNameCn(s)
return su
}
// SetNillableName sets the "name" field if the given value is not nil.
func (su *SeriesUpdate) SetNillableName(s *string) *SeriesUpdate {
// SetNillableNameCn sets the "name_cn" field if the given value is not nil.
func (su *SeriesUpdate) SetNillableNameCn(s *string) *SeriesUpdate {
if s != nil {
su.SetName(*s)
su.SetNameCn(*s)
}
return su
}
@@ -98,12 +98,6 @@ func (su *SeriesUpdate) SetNillableNameEn(s *string) *SeriesUpdate {
return su
}
// ClearNameEn clears the value of the "name_en" field.
func (su *SeriesUpdate) ClearNameEn() *SeriesUpdate {
su.mutation.ClearNameEn()
return su
}
// SetOriginalName sets the "original_name" field.
func (su *SeriesUpdate) SetOriginalName(s string) *SeriesUpdate {
su.mutation.SetOriginalName(s)
@@ -310,15 +304,12 @@ func (su *SeriesUpdate) sqlSave(ctx context.Context) (n int, err error) {
if su.mutation.ImdbIDCleared() {
_spec.ClearField(series.FieldImdbID, field.TypeString)
}
if value, ok := su.mutation.Name(); ok {
_spec.SetField(series.FieldName, field.TypeString, value)
if value, ok := su.mutation.NameCn(); ok {
_spec.SetField(series.FieldNameCn, field.TypeString, value)
}
if value, ok := su.mutation.NameEn(); ok {
_spec.SetField(series.FieldNameEn, field.TypeString, value)
}
if su.mutation.NameEnCleared() {
_spec.ClearField(series.FieldNameEn, field.TypeString)
}
if value, ok := su.mutation.OriginalName(); ok {
_spec.SetField(series.FieldOriginalName, field.TypeString, value)
}
@@ -455,16 +446,16 @@ func (suo *SeriesUpdateOne) ClearImdbID() *SeriesUpdateOne {
return suo
}
// SetName sets the "name" field.
func (suo *SeriesUpdateOne) SetName(s string) *SeriesUpdateOne {
suo.mutation.SetName(s)
// SetNameCn sets the "name_cn" field.
func (suo *SeriesUpdateOne) SetNameCn(s string) *SeriesUpdateOne {
suo.mutation.SetNameCn(s)
return suo
}
// SetNillableName sets the "name" field if the given value is not nil.
func (suo *SeriesUpdateOne) SetNillableName(s *string) *SeriesUpdateOne {
// SetNillableNameCn sets the "name_cn" field if the given value is not nil.
func (suo *SeriesUpdateOne) SetNillableNameCn(s *string) *SeriesUpdateOne {
if s != nil {
suo.SetName(*s)
suo.SetNameCn(*s)
}
return suo
}
@@ -483,12 +474,6 @@ func (suo *SeriesUpdateOne) SetNillableNameEn(s *string) *SeriesUpdateOne {
return suo
}
// ClearNameEn clears the value of the "name_en" field.
func (suo *SeriesUpdateOne) ClearNameEn() *SeriesUpdateOne {
suo.mutation.ClearNameEn()
return suo
}
// SetOriginalName sets the "original_name" field.
func (suo *SeriesUpdateOne) SetOriginalName(s string) *SeriesUpdateOne {
suo.mutation.SetOriginalName(s)
@@ -725,15 +710,12 @@ func (suo *SeriesUpdateOne) sqlSave(ctx context.Context) (_node *Series, err err
if suo.mutation.ImdbIDCleared() {
_spec.ClearField(series.FieldImdbID, field.TypeString)
}
if value, ok := suo.mutation.Name(); ok {
_spec.SetField(series.FieldName, field.TypeString, value)
if value, ok := suo.mutation.NameCn(); ok {
_spec.SetField(series.FieldNameCn, field.TypeString, value)
}
if value, ok := suo.mutation.NameEn(); ok {
_spec.SetField(series.FieldNameEn, field.TypeString, value)
}
if suo.mutation.NameEnCleared() {
_spec.ClearField(series.FieldNameEn, field.TypeString)
}
if value, ok := suo.mutation.OriginalName(); ok {
_spec.SetField(series.FieldOriginalName, field.TypeString, value)
}

10
go.sum
View File

@@ -89,6 +89,8 @@ github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0V
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM=
@@ -100,6 +102,8 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
@@ -123,6 +127,8 @@ github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.19.0 h1:RWq5SEjt8o25SROyN3z2OrDB9l7RPd3lwTWU8EcEdcI=
@@ -169,6 +175,8 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
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.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -180,6 +188,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
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.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=

View File

@@ -1,6 +1,7 @@
package server
import (
"net/http"
"polaris/db"
"polaris/log"
"polaris/pkg/tmdb"
@@ -42,6 +43,7 @@ func (s *Server) Serve() error {
api := s.r.Group("/api/v1")
api.Use(s.authModdleware)
api.StaticFS("/img", http.Dir(db.ImgPath))
setting := api.Group("/setting")
{

View File

@@ -1,11 +1,17 @@
package server
import (
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"polaris/db"
"polaris/ent"
"polaris/log"
"strconv"
tmdb "github.com/cyruzin/golang-tmdb"
"github.com/gin-gonic/gin"
"github.com/pkg/errors"
)
@@ -38,13 +44,21 @@ func (s *Server) AddWatchlist(c *gin.Context) (interface{}, error) {
if err := c.ShouldBindJSON(&in); err != nil {
return nil, errors.Wrap(err, "bind query")
}
detail, err := s.MustTMDB().GetTvDetails(in.TmdbID, s.language)
detailCn, err := s.MustTMDB().GetTvDetails(in.TmdbID, db.LanguageCN)
if err != nil {
return nil, errors.Wrap(err, "get tv detail")
}
log.Infof("find detail for tv id %d: %v", in.TmdbID, detail)
detailEn, _ := s.MustTMDB().GetTvDetails(in.TmdbID, "en-US")
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 {
@@ -69,15 +83,45 @@ func (s *Server) AddWatchlist(c *gin.Context) (interface{}, error) {
epIds = append(epIds, epid)
}
}
_, err = s.db.AddWatchlist(in.StorageID, nameEn, detail, epIds, db.R1080p)
r, err := s.db.AddWatchlist(in.StorageID, nameCn, nameEn, detail, epIds, db.R1080p)
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)
}
}()
log.Infof("add tv %s to watchlist success", detail.Name)
return nil, nil
}
func (s *Server) downloadPoster(path string, seriesId int) error{
var tmdbImgBaseUrl = "https://image.tmdb.org/t/p/w500/"
url := tmdbImgBaseUrl + path
log.Infof("try to download poster: %v", url)
var resp, err = http.Get(url)
if err != nil {
return errors.Wrap(err, "http get")
}
targetDir := fmt.Sprintf("%v/%d", db.ImgPath, seriesId)
os.MkdirAll(targetDir, 0777)
ext := filepath.Ext(path)
targetFile := filepath.Join(targetDir, "poster"+ ext)
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("poster successfully downlaoded: %v", targetFile)
return nil
}
func (s *Server) GetWatchlist(c *gin.Context) (interface{}, error) {
list := s.db.GetWatchlist()
return list, nil

View File

@@ -12,14 +12,11 @@ import 'package:ui/tv_details.dart';
import 'package:ui/weclome.dart';
void main() {
runApp(MyApp());
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
final GlobalKey<NavigatorState> _rootNavigatorKey =
GlobalKey<NavigatorState>();
MyApp({super.key});
const MyApp({super.key});
// This widget is the root of your application.
@override

View File

@@ -21,6 +21,7 @@ class APIs {
static final loginUrl = "$_baseUrl/api/login";
static final loginSettingUrl = "$_baseUrl/api/v1/setting/auth";
static final activityUrl = "$_baseUrl/api/v1/activity/";
static final imagesUrl = "$_baseUrl/api/v1/img";
static const tmdbImgBaseUrl = "https://image.tmdb.org/t/p/w500/";

View File

@@ -1,6 +1,5 @@
import 'dart:async';
import 'package:dio/dio.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:ui/providers/APIs.dart';
import 'package:ui/providers/server_response.dart';
@@ -74,7 +73,7 @@ class SeriesDetails {
SeriesDetails.fromJson(Map<String, dynamic> json) {
id = json['id'];
tmdbId = json['tmdb_id'];
name = json['name'];
name = json['name_cn'];
originalName = json['original_name'];
overview = json['overview'];
path = json['path'];

View File

@@ -133,7 +133,7 @@ class TvSeries {
TvSeries.fromJson(Map<String, dynamic> json) {
id = json['id'];
tmdbId = json['tmdb_id'];
name = json['name'];
name = json['name_cn'];
originalName = json['original_name'];
overview = json['overview'];
path = json['path'];

View File

@@ -110,7 +110,7 @@ class _TvDetailsPageState extends ConsumerState<TvDetailsPage> {
width: 150,
height: 200,
child: Image.network(
APIs.tmdbImgBaseUrl + details!.posterPath!,
"${APIs.imagesUrl}/${details.id}/poster.jpg",
fit: BoxFit.contain,
),
),

View File

@@ -36,7 +36,7 @@ class WelcomePage extends ConsumerWidget {
children: <Widget>[
Flexible(
child: Image.network(
APIs.tmdbImgBaseUrl + item.posterPath!,
"${APIs.imagesUrl}/${item.id}/poster.jpg" ,
fit: BoxFit.contain,
),
),

View File

@@ -23,13 +23,13 @@
<!-- iOS meta tags & icons -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="ui">
<meta name="apple-mobile-web-app-title" content="Polaris">
<link rel="apple-touch-icon" href="icons/Icon-192.png">
<!-- Favicon -->
<link rel="icon" type="image/png" href="favicon.png"/>
<title>ui</title>
<title>Polaris</title>
<link rel="manifest" href="manifest.json">
</head>
<body>