diff --git a/ent/media.go b/ent/media.go index abee565..d72451c 100644 --- a/ent/media.go +++ b/ent/media.go @@ -41,6 +41,8 @@ type Media struct { StorageID int `json:"storage_id,omitempty"` // TargetDir holds the value of the "target_dir" field. TargetDir string `json:"target_dir,omitempty"` + // tv series only + DownloadHistoryEpisodes bool `json:"download_history_episodes,omitempty"` // Edges holds the relations/edges for other nodes in the graph. // The values are being populated by the MediaQuery when eager-loading is set. Edges MediaEdges `json:"edges"` @@ -70,6 +72,8 @@ func (*Media) scanValues(columns []string) ([]any, error) { values := make([]any, len(columns)) for i := range columns { switch columns[i] { + case media.FieldDownloadHistoryEpisodes: + values[i] = new(sql.NullBool) case media.FieldID, media.FieldTmdbID, media.FieldStorageID: values[i] = new(sql.NullInt64) case media.FieldImdbID, media.FieldMediaType, media.FieldNameCn, media.FieldNameEn, media.FieldOriginalName, media.FieldOverview, media.FieldAirDate, media.FieldResolution, media.FieldTargetDir: @@ -169,6 +173,12 @@ func (m *Media) assignValues(columns []string, values []any) error { } else if value.Valid { m.TargetDir = value.String } + case media.FieldDownloadHistoryEpisodes: + if value, ok := values[i].(*sql.NullBool); !ok { + return fmt.Errorf("unexpected type %T for field download_history_episodes", values[i]) + } else if value.Valid { + m.DownloadHistoryEpisodes = value.Bool + } default: m.selectValues.Set(columns[i], values[i]) } @@ -245,6 +255,9 @@ func (m *Media) String() string { builder.WriteString(", ") builder.WriteString("target_dir=") builder.WriteString(m.TargetDir) + builder.WriteString(", ") + builder.WriteString("download_history_episodes=") + builder.WriteString(fmt.Sprintf("%v", m.DownloadHistoryEpisodes)) builder.WriteByte(')') return builder.String() } diff --git a/ent/media/media.go b/ent/media/media.go index 7058446..200a86a 100644 --- a/ent/media/media.go +++ b/ent/media/media.go @@ -39,6 +39,8 @@ const ( FieldStorageID = "storage_id" // FieldTargetDir holds the string denoting the target_dir field in the database. FieldTargetDir = "target_dir" + // FieldDownloadHistoryEpisodes holds the string denoting the download_history_episodes field in the database. + FieldDownloadHistoryEpisodes = "download_history_episodes" // EdgeEpisodes holds the string denoting the episodes edge name in mutations. EdgeEpisodes = "episodes" // Table holds the table name of the media in the database. @@ -67,6 +69,7 @@ var Columns = []string{ FieldResolution, FieldStorageID, FieldTargetDir, + FieldDownloadHistoryEpisodes, } // ValidColumn reports if the column name is valid (part of the table columns). @@ -84,6 +87,8 @@ var ( DefaultCreatedAt time.Time // DefaultAirDate holds the default value on creation for the "air_date" field. DefaultAirDate string + // DefaultDownloadHistoryEpisodes holds the default value on creation for the "download_history_episodes" field. + DefaultDownloadHistoryEpisodes bool ) // MediaType defines the type for the "media_type" enum field. @@ -204,6 +209,11 @@ func ByTargetDir(opts ...sql.OrderTermOption) OrderOption { return sql.OrderByField(FieldTargetDir, opts...).ToFunc() } +// ByDownloadHistoryEpisodes orders the results by the download_history_episodes field. +func ByDownloadHistoryEpisodes(opts ...sql.OrderTermOption) OrderOption { + return sql.OrderByField(FieldDownloadHistoryEpisodes, opts...).ToFunc() +} + // ByEpisodesCount orders the results by episodes count. func ByEpisodesCount(opts ...sql.OrderTermOption) OrderOption { return func(s *sql.Selector) { diff --git a/ent/media/where.go b/ent/media/where.go index 8359a7b..72f130a 100644 --- a/ent/media/where.go +++ b/ent/media/where.go @@ -105,6 +105,11 @@ func TargetDir(v string) predicate.Media { return predicate.Media(sql.FieldEQ(FieldTargetDir, v)) } +// DownloadHistoryEpisodes applies equality check predicate on the "download_history_episodes" field. It's identical to DownloadHistoryEpisodesEQ. +func DownloadHistoryEpisodes(v bool) predicate.Media { + return predicate.Media(sql.FieldEQ(FieldDownloadHistoryEpisodes, v)) +} + // TmdbIDEQ applies the EQ predicate on the "tmdb_id" field. func TmdbIDEQ(v int) predicate.Media { return predicate.Media(sql.FieldEQ(FieldTmdbID, v)) @@ -750,6 +755,26 @@ func TargetDirContainsFold(v string) predicate.Media { return predicate.Media(sql.FieldContainsFold(FieldTargetDir, v)) } +// DownloadHistoryEpisodesEQ applies the EQ predicate on the "download_history_episodes" field. +func DownloadHistoryEpisodesEQ(v bool) predicate.Media { + return predicate.Media(sql.FieldEQ(FieldDownloadHistoryEpisodes, v)) +} + +// DownloadHistoryEpisodesNEQ applies the NEQ predicate on the "download_history_episodes" field. +func DownloadHistoryEpisodesNEQ(v bool) predicate.Media { + return predicate.Media(sql.FieldNEQ(FieldDownloadHistoryEpisodes, v)) +} + +// DownloadHistoryEpisodesIsNil applies the IsNil predicate on the "download_history_episodes" field. +func DownloadHistoryEpisodesIsNil() predicate.Media { + return predicate.Media(sql.FieldIsNull(FieldDownloadHistoryEpisodes)) +} + +// DownloadHistoryEpisodesNotNil applies the NotNil predicate on the "download_history_episodes" field. +func DownloadHistoryEpisodesNotNil() predicate.Media { + return predicate.Media(sql.FieldNotNull(FieldDownloadHistoryEpisodes)) +} + // HasEpisodes applies the HasEdge predicate on the "episodes" edge. func HasEpisodes() predicate.Media { return predicate.Media(func(s *sql.Selector) { diff --git a/ent/media_create.go b/ent/media_create.go index 2e3544f..ac39762 100644 --- a/ent/media_create.go +++ b/ent/media_create.go @@ -141,6 +141,20 @@ func (mc *MediaCreate) SetNillableTargetDir(s *string) *MediaCreate { return mc } +// SetDownloadHistoryEpisodes sets the "download_history_episodes" field. +func (mc *MediaCreate) SetDownloadHistoryEpisodes(b bool) *MediaCreate { + mc.mutation.SetDownloadHistoryEpisodes(b) + return mc +} + +// SetNillableDownloadHistoryEpisodes sets the "download_history_episodes" field if the given value is not nil. +func (mc *MediaCreate) SetNillableDownloadHistoryEpisodes(b *bool) *MediaCreate { + if b != nil { + mc.SetDownloadHistoryEpisodes(*b) + } + return mc +} + // AddEpisodeIDs adds the "episodes" edge to the Episode entity by IDs. func (mc *MediaCreate) AddEpisodeIDs(ids ...int) *MediaCreate { mc.mutation.AddEpisodeIDs(ids...) @@ -203,6 +217,10 @@ func (mc *MediaCreate) defaults() { v := media.DefaultResolution mc.mutation.SetResolution(v) } + if _, ok := mc.mutation.DownloadHistoryEpisodes(); !ok { + v := media.DefaultDownloadHistoryEpisodes + mc.mutation.SetDownloadHistoryEpisodes(v) + } } // check runs all checks and user-defined validators on the builder. @@ -318,6 +336,10 @@ func (mc *MediaCreate) createSpec() (*Media, *sqlgraph.CreateSpec) { _spec.SetField(media.FieldTargetDir, field.TypeString, value) _node.TargetDir = value } + if value, ok := mc.mutation.DownloadHistoryEpisodes(); ok { + _spec.SetField(media.FieldDownloadHistoryEpisodes, field.TypeBool, value) + _node.DownloadHistoryEpisodes = value + } if nodes := mc.mutation.EpisodesIDs(); len(nodes) > 0 { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.O2M, diff --git a/ent/media_update.go b/ent/media_update.go index 34bd88b..94e2bff 100644 --- a/ent/media_update.go +++ b/ent/media_update.go @@ -229,6 +229,26 @@ func (mu *MediaUpdate) ClearTargetDir() *MediaUpdate { return mu } +// SetDownloadHistoryEpisodes sets the "download_history_episodes" field. +func (mu *MediaUpdate) SetDownloadHistoryEpisodes(b bool) *MediaUpdate { + mu.mutation.SetDownloadHistoryEpisodes(b) + return mu +} + +// SetNillableDownloadHistoryEpisodes sets the "download_history_episodes" field if the given value is not nil. +func (mu *MediaUpdate) SetNillableDownloadHistoryEpisodes(b *bool) *MediaUpdate { + if b != nil { + mu.SetDownloadHistoryEpisodes(*b) + } + return mu +} + +// ClearDownloadHistoryEpisodes clears the value of the "download_history_episodes" field. +func (mu *MediaUpdate) ClearDownloadHistoryEpisodes() *MediaUpdate { + mu.mutation.ClearDownloadHistoryEpisodes() + return mu +} + // AddEpisodeIDs adds the "episodes" edge to the Episode entity by IDs. func (mu *MediaUpdate) AddEpisodeIDs(ids ...int) *MediaUpdate { mu.mutation.AddEpisodeIDs(ids...) @@ -375,6 +395,12 @@ func (mu *MediaUpdate) sqlSave(ctx context.Context) (n int, err error) { if mu.mutation.TargetDirCleared() { _spec.ClearField(media.FieldTargetDir, field.TypeString) } + if value, ok := mu.mutation.DownloadHistoryEpisodes(); ok { + _spec.SetField(media.FieldDownloadHistoryEpisodes, field.TypeBool, value) + } + if mu.mutation.DownloadHistoryEpisodesCleared() { + _spec.ClearField(media.FieldDownloadHistoryEpisodes, field.TypeBool) + } if mu.mutation.EpisodesCleared() { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.O2M, @@ -640,6 +666,26 @@ func (muo *MediaUpdateOne) ClearTargetDir() *MediaUpdateOne { return muo } +// SetDownloadHistoryEpisodes sets the "download_history_episodes" field. +func (muo *MediaUpdateOne) SetDownloadHistoryEpisodes(b bool) *MediaUpdateOne { + muo.mutation.SetDownloadHistoryEpisodes(b) + return muo +} + +// SetNillableDownloadHistoryEpisodes sets the "download_history_episodes" field if the given value is not nil. +func (muo *MediaUpdateOne) SetNillableDownloadHistoryEpisodes(b *bool) *MediaUpdateOne { + if b != nil { + muo.SetDownloadHistoryEpisodes(*b) + } + return muo +} + +// ClearDownloadHistoryEpisodes clears the value of the "download_history_episodes" field. +func (muo *MediaUpdateOne) ClearDownloadHistoryEpisodes() *MediaUpdateOne { + muo.mutation.ClearDownloadHistoryEpisodes() + return muo +} + // AddEpisodeIDs adds the "episodes" edge to the Episode entity by IDs. func (muo *MediaUpdateOne) AddEpisodeIDs(ids ...int) *MediaUpdateOne { muo.mutation.AddEpisodeIDs(ids...) @@ -816,6 +862,12 @@ func (muo *MediaUpdateOne) sqlSave(ctx context.Context) (_node *Media, err error if muo.mutation.TargetDirCleared() { _spec.ClearField(media.FieldTargetDir, field.TypeString) } + if value, ok := muo.mutation.DownloadHistoryEpisodes(); ok { + _spec.SetField(media.FieldDownloadHistoryEpisodes, field.TypeBool, value) + } + if muo.mutation.DownloadHistoryEpisodesCleared() { + _spec.ClearField(media.FieldDownloadHistoryEpisodes, field.TypeBool) + } if muo.mutation.EpisodesCleared() { edge := &sqlgraph.EdgeSpec{ Rel: sqlgraph.O2M, diff --git a/ent/migrate/schema.go b/ent/migrate/schema.go index 635e552..622b3a7 100644 --- a/ent/migrate/schema.go +++ b/ent/migrate/schema.go @@ -102,6 +102,7 @@ var ( {Name: "resolution", Type: field.TypeEnum, Enums: []string{"720p", "1080p", "4k"}, Default: "1080p"}, {Name: "storage_id", Type: field.TypeInt, Nullable: true}, {Name: "target_dir", Type: field.TypeString, Nullable: true}, + {Name: "download_history_episodes", Type: field.TypeBool, Nullable: true, Default: false}, } // MediaTable holds the schema information for the "media" table. MediaTable = &schema.Table{ diff --git a/ent/mutation.go b/ent/mutation.go index 47205fa..70c7437 100644 --- a/ent/mutation.go +++ b/ent/mutation.go @@ -3129,30 +3129,31 @@ func (m *IndexersMutation) ResetEdge(name string) error { // MediaMutation represents an operation that mutates the Media nodes in the graph. type MediaMutation struct { config - op Op - typ string - id *int - tmdb_id *int - addtmdb_id *int - imdb_id *string - media_type *media.MediaType - name_cn *string - name_en *string - original_name *string - overview *string - created_at *time.Time - air_date *string - resolution *media.Resolution - storage_id *int - addstorage_id *int - target_dir *string - clearedFields map[string]struct{} - episodes map[int]struct{} - removedepisodes map[int]struct{} - clearedepisodes bool - done bool - oldValue func(context.Context) (*Media, error) - predicates []predicate.Media + op Op + typ string + id *int + tmdb_id *int + addtmdb_id *int + imdb_id *string + media_type *media.MediaType + name_cn *string + name_en *string + original_name *string + overview *string + created_at *time.Time + air_date *string + resolution *media.Resolution + storage_id *int + addstorage_id *int + target_dir *string + download_history_episodes *bool + clearedFields map[string]struct{} + episodes map[int]struct{} + removedepisodes map[int]struct{} + clearedepisodes bool + done bool + oldValue func(context.Context) (*Media, error) + predicates []predicate.Media } var _ ent.Mutation = (*MediaMutation)(nil) @@ -3765,6 +3766,55 @@ func (m *MediaMutation) ResetTargetDir() { delete(m.clearedFields, media.FieldTargetDir) } +// SetDownloadHistoryEpisodes sets the "download_history_episodes" field. +func (m *MediaMutation) SetDownloadHistoryEpisodes(b bool) { + m.download_history_episodes = &b +} + +// DownloadHistoryEpisodes returns the value of the "download_history_episodes" field in the mutation. +func (m *MediaMutation) DownloadHistoryEpisodes() (r bool, exists bool) { + v := m.download_history_episodes + if v == nil { + return + } + return *v, true +} + +// OldDownloadHistoryEpisodes returns the old "download_history_episodes" field's value of the Media entity. +// If the Media 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 *MediaMutation) OldDownloadHistoryEpisodes(ctx context.Context) (v bool, err error) { + if !m.op.Is(OpUpdateOne) { + return v, errors.New("OldDownloadHistoryEpisodes is only allowed on UpdateOne operations") + } + if m.id == nil || m.oldValue == nil { + return v, errors.New("OldDownloadHistoryEpisodes requires an ID field in the mutation") + } + oldValue, err := m.oldValue(ctx) + if err != nil { + return v, fmt.Errorf("querying old value for OldDownloadHistoryEpisodes: %w", err) + } + return oldValue.DownloadHistoryEpisodes, nil +} + +// ClearDownloadHistoryEpisodes clears the value of the "download_history_episodes" field. +func (m *MediaMutation) ClearDownloadHistoryEpisodes() { + m.download_history_episodes = nil + m.clearedFields[media.FieldDownloadHistoryEpisodes] = struct{}{} +} + +// DownloadHistoryEpisodesCleared returns if the "download_history_episodes" field was cleared in this mutation. +func (m *MediaMutation) DownloadHistoryEpisodesCleared() bool { + _, ok := m.clearedFields[media.FieldDownloadHistoryEpisodes] + return ok +} + +// ResetDownloadHistoryEpisodes resets all changes to the "download_history_episodes" field. +func (m *MediaMutation) ResetDownloadHistoryEpisodes() { + m.download_history_episodes = nil + delete(m.clearedFields, media.FieldDownloadHistoryEpisodes) +} + // AddEpisodeIDs adds the "episodes" edge to the Episode entity by ids. func (m *MediaMutation) AddEpisodeIDs(ids ...int) { if m.episodes == nil { @@ -3853,7 +3903,7 @@ func (m *MediaMutation) Type() string { // order to get all numeric fields that were incremented/decremented, call // AddedFields(). func (m *MediaMutation) Fields() []string { - fields := make([]string, 0, 12) + fields := make([]string, 0, 13) if m.tmdb_id != nil { fields = append(fields, media.FieldTmdbID) } @@ -3890,6 +3940,9 @@ func (m *MediaMutation) Fields() []string { if m.target_dir != nil { fields = append(fields, media.FieldTargetDir) } + if m.download_history_episodes != nil { + fields = append(fields, media.FieldDownloadHistoryEpisodes) + } return fields } @@ -3922,6 +3975,8 @@ func (m *MediaMutation) Field(name string) (ent.Value, bool) { return m.StorageID() case media.FieldTargetDir: return m.TargetDir() + case media.FieldDownloadHistoryEpisodes: + return m.DownloadHistoryEpisodes() } return nil, false } @@ -3955,6 +4010,8 @@ func (m *MediaMutation) OldField(ctx context.Context, name string) (ent.Value, e return m.OldStorageID(ctx) case media.FieldTargetDir: return m.OldTargetDir(ctx) + case media.FieldDownloadHistoryEpisodes: + return m.OldDownloadHistoryEpisodes(ctx) } return nil, fmt.Errorf("unknown Media field %s", name) } @@ -4048,6 +4105,13 @@ func (m *MediaMutation) SetField(name string, value ent.Value) error { } m.SetTargetDir(v) return nil + case media.FieldDownloadHistoryEpisodes: + v, ok := value.(bool) + if !ok { + return fmt.Errorf("unexpected type %T for field %s", value, name) + } + m.SetDownloadHistoryEpisodes(v) + return nil } return fmt.Errorf("unknown Media field %s", name) } @@ -4114,6 +4178,9 @@ func (m *MediaMutation) ClearedFields() []string { if m.FieldCleared(media.FieldTargetDir) { fields = append(fields, media.FieldTargetDir) } + if m.FieldCleared(media.FieldDownloadHistoryEpisodes) { + fields = append(fields, media.FieldDownloadHistoryEpisodes) + } return fields } @@ -4137,6 +4204,9 @@ func (m *MediaMutation) ClearField(name string) error { case media.FieldTargetDir: m.ClearTargetDir() return nil + case media.FieldDownloadHistoryEpisodes: + m.ClearDownloadHistoryEpisodes() + return nil } return fmt.Errorf("unknown Media nullable field %s", name) } @@ -4181,6 +4251,9 @@ func (m *MediaMutation) ResetField(name string) error { case media.FieldTargetDir: m.ResetTargetDir() return nil + case media.FieldDownloadHistoryEpisodes: + m.ResetDownloadHistoryEpisodes() + return nil } return fmt.Errorf("unknown Media field %s", name) } diff --git a/ent/runtime.go b/ent/runtime.go index db801ea..95bd1fc 100644 --- a/ent/runtime.go +++ b/ent/runtime.go @@ -70,6 +70,10 @@ func init() { mediaDescAirDate := mediaFields[8].Descriptor() // media.DefaultAirDate holds the default value on creation for the air_date field. media.DefaultAirDate = mediaDescAirDate.Default.(string) + // mediaDescDownloadHistoryEpisodes is the schema descriptor for download_history_episodes field. + mediaDescDownloadHistoryEpisodes := mediaFields[12].Descriptor() + // media.DefaultDownloadHistoryEpisodes holds the default value on creation for the download_history_episodes field. + media.DefaultDownloadHistoryEpisodes = mediaDescDownloadHistoryEpisodes.Default.(bool) storageFields := schema.Storage{}.Fields() _ = storageFields // storageDescDeleted is the schema descriptor for deleted field. diff --git a/ent/schema/media.go b/ent/schema/media.go index 48db8e2..962a336 100644 --- a/ent/schema/media.go +++ b/ent/schema/media.go @@ -28,7 +28,7 @@ func (Media) Fields() []ent.Field { field.Enum("resolution").Values("720p", "1080p", "4k").Default("1080p"), field.Int("storage_id").Optional(), field.String("target_dir").Optional(), - //field.Bool("download_history_episodes").Optional().Default(false).Comment("tv series only"), + field.Bool("download_history_episodes").Optional().Default(false).Comment("tv series only"), } } diff --git a/server/scheduler.go b/server/scheduler.go index f6de489..762d07f 100644 --- a/server/scheduler.go +++ b/server/scheduler.go @@ -221,14 +221,17 @@ func (s *Server) downloadTvSeries() { for _, series := range allSeries { tvDetail := s.db.GetMediaDetails(series.ID) for _, ep := range tvDetail.Episodes { - t, err := time.Parse("2006-01-02", ep.AirDate) - if err != nil { - log.Error("air date not known, skip: %v", ep.Title) - continue - } - if series.CreatedAt.Sub(t) > 24*time.Hour { //剧集在加入watchlist之前,不去下载 - continue + if !series.DownloadHistoryEpisodes { //设置不下载历史已播出剧集,只下载将来剧集 + t, err := time.Parse("2006-01-02", ep.AirDate) + if err != nil { + log.Error("air date not known, skip: %v", ep.Title) + continue + } + if series.CreatedAt.Sub(t) > 24*time.Hour { //剧集在加入watchlist之前,不去下载 + continue + } } + if ep.Status != episode.StatusMissing { //已经下载的不去下载 continue } diff --git a/server/watchlist.go b/server/watchlist.go index 2ab4af4..723dc7d 100644 --- a/server/watchlist.go +++ b/server/watchlist.go @@ -57,10 +57,11 @@ func (s *Server) SearchMedia(c *gin.Context) (interface{}, error) { } 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"` + TmdbID int `json:"tmdb_id" binding:"required"` + StorageID int `json:"storage_id" ` + Resolution string `json:"resolution" binding:"required"` + Folder string `json:"folder"` + DownloadHistoryEpisodes bool `json:"download_history_episodes"` //for tv } func (s *Server) AddTv2Watchlist(c *gin.Context) (interface{}, error) { @@ -121,6 +122,7 @@ func (s *Server) AddTv2Watchlist(c *gin.Context) (interface{}, error) { Resolution: media.Resolution(in.Resolution), StorageID: in.StorageID, TargetDir: in.Folder, + DownloadHistoryEpisodes: in.DownloadHistoryEpisodes, }, epIds) if err != nil { return nil, errors.Wrap(err, "add to list") @@ -273,7 +275,7 @@ func (s *Server) GetTvWatchlist(c *gin.Context) (interface{}, error) { } if ep.Status == episode.StatusMissing { ms.Status = "monitoring" - } + } } } res[i] = ms diff --git a/ui/lib/providers/welcome_data.dart b/ui/lib/providers/welcome_data.dart index 68e953d..7a94581 100644 --- a/ui/lib/providers/welcome_data.dart +++ b/ui/lib/providers/welcome_data.dart @@ -84,14 +84,15 @@ class SearchPageData } Future submit2Watchlist(int tmdbId, int storageId, String resolution, - String mediaType, String folder) async { + String mediaType, String folder, bool downloadHistoryEpisodes) async { final dio = await APIs.getDio(); if (mediaType == "tv") { var resp = await dio.post(APIs.watchlistTvUrl, data: { "tmdb_id": tmdbId, "storage_id": storageId, "resolution": resolution, - "folder": folder + "folder": folder, + "download_history_episodes":downloadHistoryEpisodes }); var sp = ServerResponse.fromJson(resp.data); if (sp.code != 0) { diff --git a/ui/lib/search.dart b/ui/lib/search.dart index c9e4b26..e586de2 100644 --- a/ui/lib/search.dart +++ b/ui/lib/search.dart @@ -146,6 +146,8 @@ class _SearchPageState extends ConsumerState { int storageSelected = 0; var storage = ref.watch(storageSettingProvider); var name = ref.watch(suggestNameDataProvider(item.id!)); + bool downloadHistoryEpisodes = false; + bool buttonTapped = false; var pathController = TextEditingController(); return AlertDialog( @@ -230,6 +232,19 @@ class _SearchPageState extends ConsumerState { ), ) : Text(""), + item.mediaType == "tv" + ? SizedBox( + width: 250, + child: CheckboxListTile( + title: const Text("是否下载往期剧集"), + value: downloadHistoryEpisodes, + onChanged: (v) { + setState(() { + downloadHistoryEpisodes = v!; + }); + }), + ) + : const SizedBox(), ], ); }); @@ -254,18 +269,33 @@ class _SearchPageState extends ConsumerState { textStyle: Theme.of(context).textTheme.labelLarge, ), child: const Text('确定'), - onPressed: () { - ref + onPressed: () async { + if (buttonTapped) { + return; + } + setState(() { + buttonTapped = true; + }); + + await ref .read(searchPageDataProvider(widget.query ?? "") .notifier) - .submit2Watchlist(item.id!, storageSelected, - resSelected, item.mediaType!, pathController.text) + .submit2Watchlist( + item.id!, + storageSelected, + resSelected, + item.mediaType!, + pathController.text, + downloadHistoryEpisodes) .then((v) { Utils.showSnakeBar("添加成功"); Navigator.of(context).pop(); }).onError((error, trace) { Utils.showSnakeBar("添加失败:$error"); }); + setState(() { + buttonTapped = false; + }); }, ), ],