mirror of
https://github.com/simon-ding/polaris.git
synced 2026-02-06 15:10:49 +08:00
refactor code
This commit is contained in:
49
db/db.go
49
db/db.go
@@ -87,11 +87,9 @@ func (c *Client) generateDefaultLocalStorage() error {
|
||||
return c.AddStorage(&StorageInfo{
|
||||
Name: "local",
|
||||
Implementation: "local",
|
||||
TvPath: "/data/tv/",
|
||||
MoviePath: "/data/movies/",
|
||||
Default: true,
|
||||
Settings: map[string]string{
|
||||
"tv_path": "/data/tv/",
|
||||
"movie_path": "/data/movies/",
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -171,7 +169,6 @@ func (c *Client) GetEpisodeByID(epID int) (*ent.Episode, error) {
|
||||
return c.ent.Episode.Query().Where(episode.ID(epID)).First(context.TODO())
|
||||
}
|
||||
|
||||
|
||||
func (c *Client) UpdateEpiode(episodeId int, name, overview string) error {
|
||||
return c.ent.Episode.Update().Where(episode.ID(episodeId)).SetTitle(name).SetOverview(overview).Exec(context.TODO())
|
||||
}
|
||||
@@ -339,7 +336,9 @@ type StorageInfo struct {
|
||||
Name string `json:"name" binding:"required"`
|
||||
Implementation string `json:"implementation" binding:"required"`
|
||||
Settings map[string]string `json:"settings" binding:"required"`
|
||||
Default bool `json:"default"`
|
||||
TvPath string `json:"tv_path" binding:"required"`
|
||||
MoviePath string `json:"movie_path" binding:"required"`
|
||||
Default bool `json:"default"`
|
||||
}
|
||||
|
||||
func (s *StorageInfo) ToWebDavSetting() WebdavSetting {
|
||||
@@ -348,34 +347,29 @@ func (s *StorageInfo) ToWebDavSetting() WebdavSetting {
|
||||
}
|
||||
return WebdavSetting{
|
||||
URL: s.Settings["url"],
|
||||
TvPath: s.Settings["tv_path"],
|
||||
MoviePath: s.Settings["movie_path"],
|
||||
User: s.Settings["user"],
|
||||
Password: s.Settings["password"],
|
||||
ChangeFileHash: s.Settings["change_file_hash"],
|
||||
}
|
||||
}
|
||||
|
||||
type LocalDirSetting struct {
|
||||
TvPath string `json:"tv_path"`
|
||||
MoviePath string `json:"movie_path"`
|
||||
}
|
||||
|
||||
type WebdavSetting struct {
|
||||
URL string `json:"url"`
|
||||
TvPath string `json:"tv_path"`
|
||||
MoviePath string `json:"movie_path"`
|
||||
User string `json:"user"`
|
||||
Password string `json:"password"`
|
||||
ChangeFileHash string `json:"change_file_hash"`
|
||||
}
|
||||
|
||||
func (c *Client) AddStorage(st *StorageInfo) error {
|
||||
if !strings.HasSuffix(st.Settings["tv_path"], "/") {
|
||||
st.Settings["tv_path"] += "/"
|
||||
if !strings.HasSuffix(st.TvPath, "/") {
|
||||
st.TvPath += "/"
|
||||
}
|
||||
if !strings.HasSuffix(st.Settings["movie_path"], "/") {
|
||||
st.Settings["movie_path"] += "/"
|
||||
if !strings.HasSuffix(st.MoviePath, "/") {
|
||||
st.MoviePath += "/"
|
||||
}
|
||||
if st.Settings == nil {
|
||||
st.Settings = map[string]string{}
|
||||
}
|
||||
|
||||
data, err := json.Marshal(st.Settings)
|
||||
@@ -387,7 +381,7 @@ func (c *Client) AddStorage(st *StorageInfo) error {
|
||||
if count > 0 {
|
||||
//storage already exist, edit exist one
|
||||
return c.ent.Storage.Update().Where(storage.Name(st.Name)).
|
||||
SetImplementation(storage.Implementation(st.Implementation)).
|
||||
SetImplementation(storage.Implementation(st.Implementation)).SetTvPath(st.TvPath).SetMoviePath(st.MoviePath).
|
||||
SetSettings(string(data)).Exec(context.TODO())
|
||||
}
|
||||
countAll := c.ent.Storage.Query().Where(storage.Deleted(false)).CountX(context.TODO())
|
||||
@@ -396,7 +390,7 @@ func (c *Client) AddStorage(st *StorageInfo) error {
|
||||
st.Default = true
|
||||
}
|
||||
_, err = c.ent.Storage.Create().SetName(st.Name).
|
||||
SetImplementation(storage.Implementation(st.Implementation)).
|
||||
SetImplementation(storage.Implementation(st.Implementation)).SetTvPath(st.TvPath).SetMoviePath(st.MoviePath).
|
||||
SetSettings(string(data)).SetDefault(st.Default).Save(context.TODO())
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -417,15 +411,6 @@ type Storage struct {
|
||||
ent.Storage
|
||||
}
|
||||
|
||||
func (s *Storage) ToLocalSetting() LocalDirSetting {
|
||||
if s.Implementation != storage.ImplementationLocal {
|
||||
panic("not local storage")
|
||||
}
|
||||
var localSetting LocalDirSetting
|
||||
json.Unmarshal([]byte(s.Settings), &localSetting)
|
||||
return localSetting
|
||||
}
|
||||
|
||||
func (s *Storage) ToWebDavSetting() WebdavSetting {
|
||||
if s.Implementation != storage.ImplementationWebdav {
|
||||
panic("not webdav storage")
|
||||
@@ -435,12 +420,6 @@ func (s *Storage) ToWebDavSetting() WebdavSetting {
|
||||
return webdavSetting
|
||||
}
|
||||
|
||||
func (s *Storage) GetPath() (tvPath string, moviePath string) {
|
||||
var m map[string]string
|
||||
json.Unmarshal([]byte(s.Settings), &m)
|
||||
return m["tv_path"], m["movie_path"]
|
||||
}
|
||||
|
||||
func (c *Client) GetStorage(id int) *Storage {
|
||||
r, err := c.ent.Storage.Query().Where(storage.ID(id)).First(context.TODO())
|
||||
if err != nil {
|
||||
|
||||
@@ -142,6 +142,8 @@ var (
|
||||
{Name: "id", Type: field.TypeInt, Increment: true},
|
||||
{Name: "name", Type: field.TypeString, Unique: true},
|
||||
{Name: "implementation", Type: field.TypeEnum, Enums: []string{"webdav", "local"}},
|
||||
{Name: "tv_path", Type: field.TypeString, Nullable: true},
|
||||
{Name: "movie_path", Type: field.TypeString, Nullable: true},
|
||||
{Name: "settings", Type: field.TypeString, Nullable: true},
|
||||
{Name: "deleted", Type: field.TypeBool, Default: false},
|
||||
{Name: "default", Type: field.TypeBool, Default: false},
|
||||
|
||||
148
ent/mutation.go
148
ent/mutation.go
@@ -5327,6 +5327,8 @@ type StorageMutation struct {
|
||||
id *int
|
||||
name *string
|
||||
implementation *storage.Implementation
|
||||
tv_path *string
|
||||
movie_path *string
|
||||
settings *string
|
||||
deleted *bool
|
||||
_default *bool
|
||||
@@ -5506,6 +5508,104 @@ func (m *StorageMutation) ResetImplementation() {
|
||||
m.implementation = nil
|
||||
}
|
||||
|
||||
// SetTvPath sets the "tv_path" field.
|
||||
func (m *StorageMutation) SetTvPath(s string) {
|
||||
m.tv_path = &s
|
||||
}
|
||||
|
||||
// TvPath returns the value of the "tv_path" field in the mutation.
|
||||
func (m *StorageMutation) TvPath() (r string, exists bool) {
|
||||
v := m.tv_path
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
return *v, true
|
||||
}
|
||||
|
||||
// OldTvPath returns the old "tv_path" field's value of the Storage entity.
|
||||
// If the Storage 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 *StorageMutation) OldTvPath(ctx context.Context) (v string, err error) {
|
||||
if !m.op.Is(OpUpdateOne) {
|
||||
return v, errors.New("OldTvPath is only allowed on UpdateOne operations")
|
||||
}
|
||||
if m.id == nil || m.oldValue == nil {
|
||||
return v, errors.New("OldTvPath requires an ID field in the mutation")
|
||||
}
|
||||
oldValue, err := m.oldValue(ctx)
|
||||
if err != nil {
|
||||
return v, fmt.Errorf("querying old value for OldTvPath: %w", err)
|
||||
}
|
||||
return oldValue.TvPath, nil
|
||||
}
|
||||
|
||||
// ClearTvPath clears the value of the "tv_path" field.
|
||||
func (m *StorageMutation) ClearTvPath() {
|
||||
m.tv_path = nil
|
||||
m.clearedFields[storage.FieldTvPath] = struct{}{}
|
||||
}
|
||||
|
||||
// TvPathCleared returns if the "tv_path" field was cleared in this mutation.
|
||||
func (m *StorageMutation) TvPathCleared() bool {
|
||||
_, ok := m.clearedFields[storage.FieldTvPath]
|
||||
return ok
|
||||
}
|
||||
|
||||
// ResetTvPath resets all changes to the "tv_path" field.
|
||||
func (m *StorageMutation) ResetTvPath() {
|
||||
m.tv_path = nil
|
||||
delete(m.clearedFields, storage.FieldTvPath)
|
||||
}
|
||||
|
||||
// SetMoviePath sets the "movie_path" field.
|
||||
func (m *StorageMutation) SetMoviePath(s string) {
|
||||
m.movie_path = &s
|
||||
}
|
||||
|
||||
// MoviePath returns the value of the "movie_path" field in the mutation.
|
||||
func (m *StorageMutation) MoviePath() (r string, exists bool) {
|
||||
v := m.movie_path
|
||||
if v == nil {
|
||||
return
|
||||
}
|
||||
return *v, true
|
||||
}
|
||||
|
||||
// OldMoviePath returns the old "movie_path" field's value of the Storage entity.
|
||||
// If the Storage 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 *StorageMutation) OldMoviePath(ctx context.Context) (v string, err error) {
|
||||
if !m.op.Is(OpUpdateOne) {
|
||||
return v, errors.New("OldMoviePath is only allowed on UpdateOne operations")
|
||||
}
|
||||
if m.id == nil || m.oldValue == nil {
|
||||
return v, errors.New("OldMoviePath requires an ID field in the mutation")
|
||||
}
|
||||
oldValue, err := m.oldValue(ctx)
|
||||
if err != nil {
|
||||
return v, fmt.Errorf("querying old value for OldMoviePath: %w", err)
|
||||
}
|
||||
return oldValue.MoviePath, nil
|
||||
}
|
||||
|
||||
// ClearMoviePath clears the value of the "movie_path" field.
|
||||
func (m *StorageMutation) ClearMoviePath() {
|
||||
m.movie_path = nil
|
||||
m.clearedFields[storage.FieldMoviePath] = struct{}{}
|
||||
}
|
||||
|
||||
// MoviePathCleared returns if the "movie_path" field was cleared in this mutation.
|
||||
func (m *StorageMutation) MoviePathCleared() bool {
|
||||
_, ok := m.clearedFields[storage.FieldMoviePath]
|
||||
return ok
|
||||
}
|
||||
|
||||
// ResetMoviePath resets all changes to the "movie_path" field.
|
||||
func (m *StorageMutation) ResetMoviePath() {
|
||||
m.movie_path = nil
|
||||
delete(m.clearedFields, storage.FieldMoviePath)
|
||||
}
|
||||
|
||||
// SetSettings sets the "settings" field.
|
||||
func (m *StorageMutation) SetSettings(s string) {
|
||||
m.settings = &s
|
||||
@@ -5661,13 +5761,19 @@ func (m *StorageMutation) Type() string {
|
||||
// order to get all numeric fields that were incremented/decremented, call
|
||||
// AddedFields().
|
||||
func (m *StorageMutation) Fields() []string {
|
||||
fields := make([]string, 0, 5)
|
||||
fields := make([]string, 0, 7)
|
||||
if m.name != nil {
|
||||
fields = append(fields, storage.FieldName)
|
||||
}
|
||||
if m.implementation != nil {
|
||||
fields = append(fields, storage.FieldImplementation)
|
||||
}
|
||||
if m.tv_path != nil {
|
||||
fields = append(fields, storage.FieldTvPath)
|
||||
}
|
||||
if m.movie_path != nil {
|
||||
fields = append(fields, storage.FieldMoviePath)
|
||||
}
|
||||
if m.settings != nil {
|
||||
fields = append(fields, storage.FieldSettings)
|
||||
}
|
||||
@@ -5689,6 +5795,10 @@ func (m *StorageMutation) Field(name string) (ent.Value, bool) {
|
||||
return m.Name()
|
||||
case storage.FieldImplementation:
|
||||
return m.Implementation()
|
||||
case storage.FieldTvPath:
|
||||
return m.TvPath()
|
||||
case storage.FieldMoviePath:
|
||||
return m.MoviePath()
|
||||
case storage.FieldSettings:
|
||||
return m.Settings()
|
||||
case storage.FieldDeleted:
|
||||
@@ -5708,6 +5818,10 @@ func (m *StorageMutation) OldField(ctx context.Context, name string) (ent.Value,
|
||||
return m.OldName(ctx)
|
||||
case storage.FieldImplementation:
|
||||
return m.OldImplementation(ctx)
|
||||
case storage.FieldTvPath:
|
||||
return m.OldTvPath(ctx)
|
||||
case storage.FieldMoviePath:
|
||||
return m.OldMoviePath(ctx)
|
||||
case storage.FieldSettings:
|
||||
return m.OldSettings(ctx)
|
||||
case storage.FieldDeleted:
|
||||
@@ -5737,6 +5851,20 @@ func (m *StorageMutation) SetField(name string, value ent.Value) error {
|
||||
}
|
||||
m.SetImplementation(v)
|
||||
return nil
|
||||
case storage.FieldTvPath:
|
||||
v, ok := value.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||
}
|
||||
m.SetTvPath(v)
|
||||
return nil
|
||||
case storage.FieldMoviePath:
|
||||
v, ok := value.(string)
|
||||
if !ok {
|
||||
return fmt.Errorf("unexpected type %T for field %s", value, name)
|
||||
}
|
||||
m.SetMoviePath(v)
|
||||
return nil
|
||||
case storage.FieldSettings:
|
||||
v, ok := value.(string)
|
||||
if !ok {
|
||||
@@ -5788,6 +5916,12 @@ func (m *StorageMutation) AddField(name string, value ent.Value) error {
|
||||
// mutation.
|
||||
func (m *StorageMutation) ClearedFields() []string {
|
||||
var fields []string
|
||||
if m.FieldCleared(storage.FieldTvPath) {
|
||||
fields = append(fields, storage.FieldTvPath)
|
||||
}
|
||||
if m.FieldCleared(storage.FieldMoviePath) {
|
||||
fields = append(fields, storage.FieldMoviePath)
|
||||
}
|
||||
if m.FieldCleared(storage.FieldSettings) {
|
||||
fields = append(fields, storage.FieldSettings)
|
||||
}
|
||||
@@ -5805,6 +5939,12 @@ func (m *StorageMutation) FieldCleared(name string) bool {
|
||||
// error if the field is not defined in the schema.
|
||||
func (m *StorageMutation) ClearField(name string) error {
|
||||
switch name {
|
||||
case storage.FieldTvPath:
|
||||
m.ClearTvPath()
|
||||
return nil
|
||||
case storage.FieldMoviePath:
|
||||
m.ClearMoviePath()
|
||||
return nil
|
||||
case storage.FieldSettings:
|
||||
m.ClearSettings()
|
||||
return nil
|
||||
@@ -5822,6 +5962,12 @@ func (m *StorageMutation) ResetField(name string) error {
|
||||
case storage.FieldImplementation:
|
||||
m.ResetImplementation()
|
||||
return nil
|
||||
case storage.FieldTvPath:
|
||||
m.ResetTvPath()
|
||||
return nil
|
||||
case storage.FieldMoviePath:
|
||||
m.ResetMoviePath()
|
||||
return nil
|
||||
case storage.FieldSettings:
|
||||
m.ResetSettings()
|
||||
return nil
|
||||
|
||||
@@ -84,11 +84,11 @@ func init() {
|
||||
storageFields := schema.Storage{}.Fields()
|
||||
_ = storageFields
|
||||
// storageDescDeleted is the schema descriptor for deleted field.
|
||||
storageDescDeleted := storageFields[3].Descriptor()
|
||||
storageDescDeleted := storageFields[5].Descriptor()
|
||||
// storage.DefaultDeleted holds the default value on creation for the deleted field.
|
||||
storage.DefaultDeleted = storageDescDeleted.Default.(bool)
|
||||
// storageDescDefault is the schema descriptor for default field.
|
||||
storageDescDefault := storageFields[4].Descriptor()
|
||||
storageDescDefault := storageFields[6].Descriptor()
|
||||
// storage.DefaultDefault holds the default value on creation for the default field.
|
||||
storage.DefaultDefault = storageDescDefault.Default.(bool)
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@ func (Storage) Fields() []ent.Field {
|
||||
return []ent.Field{
|
||||
field.String("name").Unique(),
|
||||
field.Enum("implementation").Values("webdav", "local"),
|
||||
field.String("tv_path").Optional(),
|
||||
field.String("movie_path").Optional(),
|
||||
field.String("settings").Optional(),
|
||||
field.Bool("deleted").Default(false),
|
||||
field.Bool("default").Default(false),
|
||||
|
||||
@@ -20,6 +20,10 @@ type Storage struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
// Implementation holds the value of the "implementation" field.
|
||||
Implementation storage.Implementation `json:"implementation,omitempty"`
|
||||
// TvPath holds the value of the "tv_path" field.
|
||||
TvPath string `json:"tv_path,omitempty"`
|
||||
// MoviePath holds the value of the "movie_path" field.
|
||||
MoviePath string `json:"movie_path,omitempty"`
|
||||
// Settings holds the value of the "settings" field.
|
||||
Settings string `json:"settings,omitempty"`
|
||||
// Deleted holds the value of the "deleted" field.
|
||||
@@ -38,7 +42,7 @@ func (*Storage) scanValues(columns []string) ([]any, error) {
|
||||
values[i] = new(sql.NullBool)
|
||||
case storage.FieldID:
|
||||
values[i] = new(sql.NullInt64)
|
||||
case storage.FieldName, storage.FieldImplementation, storage.FieldSettings:
|
||||
case storage.FieldName, storage.FieldImplementation, storage.FieldTvPath, storage.FieldMoviePath, storage.FieldSettings:
|
||||
values[i] = new(sql.NullString)
|
||||
default:
|
||||
values[i] = new(sql.UnknownType)
|
||||
@@ -73,6 +77,18 @@ func (s *Storage) assignValues(columns []string, values []any) error {
|
||||
} else if value.Valid {
|
||||
s.Implementation = storage.Implementation(value.String)
|
||||
}
|
||||
case storage.FieldTvPath:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field tv_path", values[i])
|
||||
} else if value.Valid {
|
||||
s.TvPath = value.String
|
||||
}
|
||||
case storage.FieldMoviePath:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field movie_path", values[i])
|
||||
} else if value.Valid {
|
||||
s.MoviePath = value.String
|
||||
}
|
||||
case storage.FieldSettings:
|
||||
if value, ok := values[i].(*sql.NullString); !ok {
|
||||
return fmt.Errorf("unexpected type %T for field settings", values[i])
|
||||
@@ -133,6 +149,12 @@ func (s *Storage) String() string {
|
||||
builder.WriteString("implementation=")
|
||||
builder.WriteString(fmt.Sprintf("%v", s.Implementation))
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("tv_path=")
|
||||
builder.WriteString(s.TvPath)
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("movie_path=")
|
||||
builder.WriteString(s.MoviePath)
|
||||
builder.WriteString(", ")
|
||||
builder.WriteString("settings=")
|
||||
builder.WriteString(s.Settings)
|
||||
builder.WriteString(", ")
|
||||
|
||||
@@ -17,6 +17,10 @@ const (
|
||||
FieldName = "name"
|
||||
// FieldImplementation holds the string denoting the implementation field in the database.
|
||||
FieldImplementation = "implementation"
|
||||
// FieldTvPath holds the string denoting the tv_path field in the database.
|
||||
FieldTvPath = "tv_path"
|
||||
// FieldMoviePath holds the string denoting the movie_path field in the database.
|
||||
FieldMoviePath = "movie_path"
|
||||
// FieldSettings holds the string denoting the settings field in the database.
|
||||
FieldSettings = "settings"
|
||||
// FieldDeleted holds the string denoting the deleted field in the database.
|
||||
@@ -32,6 +36,8 @@ var Columns = []string{
|
||||
FieldID,
|
||||
FieldName,
|
||||
FieldImplementation,
|
||||
FieldTvPath,
|
||||
FieldMoviePath,
|
||||
FieldSettings,
|
||||
FieldDeleted,
|
||||
FieldDefault,
|
||||
@@ -95,6 +101,16 @@ func ByImplementation(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldImplementation, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByTvPath orders the results by the tv_path field.
|
||||
func ByTvPath(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldTvPath, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// ByMoviePath orders the results by the movie_path field.
|
||||
func ByMoviePath(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldMoviePath, opts...).ToFunc()
|
||||
}
|
||||
|
||||
// BySettings orders the results by the settings field.
|
||||
func BySettings(opts ...sql.OrderTermOption) OrderOption {
|
||||
return sql.OrderByField(FieldSettings, opts...).ToFunc()
|
||||
|
||||
@@ -58,6 +58,16 @@ func Name(v string) predicate.Storage {
|
||||
return predicate.Storage(sql.FieldEQ(FieldName, v))
|
||||
}
|
||||
|
||||
// TvPath applies equality check predicate on the "tv_path" field. It's identical to TvPathEQ.
|
||||
func TvPath(v string) predicate.Storage {
|
||||
return predicate.Storage(sql.FieldEQ(FieldTvPath, v))
|
||||
}
|
||||
|
||||
// MoviePath applies equality check predicate on the "movie_path" field. It's identical to MoviePathEQ.
|
||||
func MoviePath(v string) predicate.Storage {
|
||||
return predicate.Storage(sql.FieldEQ(FieldMoviePath, v))
|
||||
}
|
||||
|
||||
// Settings applies equality check predicate on the "settings" field. It's identical to SettingsEQ.
|
||||
func Settings(v string) predicate.Storage {
|
||||
return predicate.Storage(sql.FieldEQ(FieldSettings, v))
|
||||
@@ -158,6 +168,156 @@ func ImplementationNotIn(vs ...Implementation) predicate.Storage {
|
||||
return predicate.Storage(sql.FieldNotIn(FieldImplementation, vs...))
|
||||
}
|
||||
|
||||
// TvPathEQ applies the EQ predicate on the "tv_path" field.
|
||||
func TvPathEQ(v string) predicate.Storage {
|
||||
return predicate.Storage(sql.FieldEQ(FieldTvPath, v))
|
||||
}
|
||||
|
||||
// TvPathNEQ applies the NEQ predicate on the "tv_path" field.
|
||||
func TvPathNEQ(v string) predicate.Storage {
|
||||
return predicate.Storage(sql.FieldNEQ(FieldTvPath, v))
|
||||
}
|
||||
|
||||
// TvPathIn applies the In predicate on the "tv_path" field.
|
||||
func TvPathIn(vs ...string) predicate.Storage {
|
||||
return predicate.Storage(sql.FieldIn(FieldTvPath, vs...))
|
||||
}
|
||||
|
||||
// TvPathNotIn applies the NotIn predicate on the "tv_path" field.
|
||||
func TvPathNotIn(vs ...string) predicate.Storage {
|
||||
return predicate.Storage(sql.FieldNotIn(FieldTvPath, vs...))
|
||||
}
|
||||
|
||||
// TvPathGT applies the GT predicate on the "tv_path" field.
|
||||
func TvPathGT(v string) predicate.Storage {
|
||||
return predicate.Storage(sql.FieldGT(FieldTvPath, v))
|
||||
}
|
||||
|
||||
// TvPathGTE applies the GTE predicate on the "tv_path" field.
|
||||
func TvPathGTE(v string) predicate.Storage {
|
||||
return predicate.Storage(sql.FieldGTE(FieldTvPath, v))
|
||||
}
|
||||
|
||||
// TvPathLT applies the LT predicate on the "tv_path" field.
|
||||
func TvPathLT(v string) predicate.Storage {
|
||||
return predicate.Storage(sql.FieldLT(FieldTvPath, v))
|
||||
}
|
||||
|
||||
// TvPathLTE applies the LTE predicate on the "tv_path" field.
|
||||
func TvPathLTE(v string) predicate.Storage {
|
||||
return predicate.Storage(sql.FieldLTE(FieldTvPath, v))
|
||||
}
|
||||
|
||||
// TvPathContains applies the Contains predicate on the "tv_path" field.
|
||||
func TvPathContains(v string) predicate.Storage {
|
||||
return predicate.Storage(sql.FieldContains(FieldTvPath, v))
|
||||
}
|
||||
|
||||
// TvPathHasPrefix applies the HasPrefix predicate on the "tv_path" field.
|
||||
func TvPathHasPrefix(v string) predicate.Storage {
|
||||
return predicate.Storage(sql.FieldHasPrefix(FieldTvPath, v))
|
||||
}
|
||||
|
||||
// TvPathHasSuffix applies the HasSuffix predicate on the "tv_path" field.
|
||||
func TvPathHasSuffix(v string) predicate.Storage {
|
||||
return predicate.Storage(sql.FieldHasSuffix(FieldTvPath, v))
|
||||
}
|
||||
|
||||
// TvPathIsNil applies the IsNil predicate on the "tv_path" field.
|
||||
func TvPathIsNil() predicate.Storage {
|
||||
return predicate.Storage(sql.FieldIsNull(FieldTvPath))
|
||||
}
|
||||
|
||||
// TvPathNotNil applies the NotNil predicate on the "tv_path" field.
|
||||
func TvPathNotNil() predicate.Storage {
|
||||
return predicate.Storage(sql.FieldNotNull(FieldTvPath))
|
||||
}
|
||||
|
||||
// TvPathEqualFold applies the EqualFold predicate on the "tv_path" field.
|
||||
func TvPathEqualFold(v string) predicate.Storage {
|
||||
return predicate.Storage(sql.FieldEqualFold(FieldTvPath, v))
|
||||
}
|
||||
|
||||
// TvPathContainsFold applies the ContainsFold predicate on the "tv_path" field.
|
||||
func TvPathContainsFold(v string) predicate.Storage {
|
||||
return predicate.Storage(sql.FieldContainsFold(FieldTvPath, v))
|
||||
}
|
||||
|
||||
// MoviePathEQ applies the EQ predicate on the "movie_path" field.
|
||||
func MoviePathEQ(v string) predicate.Storage {
|
||||
return predicate.Storage(sql.FieldEQ(FieldMoviePath, v))
|
||||
}
|
||||
|
||||
// MoviePathNEQ applies the NEQ predicate on the "movie_path" field.
|
||||
func MoviePathNEQ(v string) predicate.Storage {
|
||||
return predicate.Storage(sql.FieldNEQ(FieldMoviePath, v))
|
||||
}
|
||||
|
||||
// MoviePathIn applies the In predicate on the "movie_path" field.
|
||||
func MoviePathIn(vs ...string) predicate.Storage {
|
||||
return predicate.Storage(sql.FieldIn(FieldMoviePath, vs...))
|
||||
}
|
||||
|
||||
// MoviePathNotIn applies the NotIn predicate on the "movie_path" field.
|
||||
func MoviePathNotIn(vs ...string) predicate.Storage {
|
||||
return predicate.Storage(sql.FieldNotIn(FieldMoviePath, vs...))
|
||||
}
|
||||
|
||||
// MoviePathGT applies the GT predicate on the "movie_path" field.
|
||||
func MoviePathGT(v string) predicate.Storage {
|
||||
return predicate.Storage(sql.FieldGT(FieldMoviePath, v))
|
||||
}
|
||||
|
||||
// MoviePathGTE applies the GTE predicate on the "movie_path" field.
|
||||
func MoviePathGTE(v string) predicate.Storage {
|
||||
return predicate.Storage(sql.FieldGTE(FieldMoviePath, v))
|
||||
}
|
||||
|
||||
// MoviePathLT applies the LT predicate on the "movie_path" field.
|
||||
func MoviePathLT(v string) predicate.Storage {
|
||||
return predicate.Storage(sql.FieldLT(FieldMoviePath, v))
|
||||
}
|
||||
|
||||
// MoviePathLTE applies the LTE predicate on the "movie_path" field.
|
||||
func MoviePathLTE(v string) predicate.Storage {
|
||||
return predicate.Storage(sql.FieldLTE(FieldMoviePath, v))
|
||||
}
|
||||
|
||||
// MoviePathContains applies the Contains predicate on the "movie_path" field.
|
||||
func MoviePathContains(v string) predicate.Storage {
|
||||
return predicate.Storage(sql.FieldContains(FieldMoviePath, v))
|
||||
}
|
||||
|
||||
// MoviePathHasPrefix applies the HasPrefix predicate on the "movie_path" field.
|
||||
func MoviePathHasPrefix(v string) predicate.Storage {
|
||||
return predicate.Storage(sql.FieldHasPrefix(FieldMoviePath, v))
|
||||
}
|
||||
|
||||
// MoviePathHasSuffix applies the HasSuffix predicate on the "movie_path" field.
|
||||
func MoviePathHasSuffix(v string) predicate.Storage {
|
||||
return predicate.Storage(sql.FieldHasSuffix(FieldMoviePath, v))
|
||||
}
|
||||
|
||||
// MoviePathIsNil applies the IsNil predicate on the "movie_path" field.
|
||||
func MoviePathIsNil() predicate.Storage {
|
||||
return predicate.Storage(sql.FieldIsNull(FieldMoviePath))
|
||||
}
|
||||
|
||||
// MoviePathNotNil applies the NotNil predicate on the "movie_path" field.
|
||||
func MoviePathNotNil() predicate.Storage {
|
||||
return predicate.Storage(sql.FieldNotNull(FieldMoviePath))
|
||||
}
|
||||
|
||||
// MoviePathEqualFold applies the EqualFold predicate on the "movie_path" field.
|
||||
func MoviePathEqualFold(v string) predicate.Storage {
|
||||
return predicate.Storage(sql.FieldEqualFold(FieldMoviePath, v))
|
||||
}
|
||||
|
||||
// MoviePathContainsFold applies the ContainsFold predicate on the "movie_path" field.
|
||||
func MoviePathContainsFold(v string) predicate.Storage {
|
||||
return predicate.Storage(sql.FieldContainsFold(FieldMoviePath, v))
|
||||
}
|
||||
|
||||
// SettingsEQ applies the EQ predicate on the "settings" field.
|
||||
func SettingsEQ(v string) predicate.Storage {
|
||||
return predicate.Storage(sql.FieldEQ(FieldSettings, v))
|
||||
|
||||
@@ -31,6 +31,34 @@ func (sc *StorageCreate) SetImplementation(s storage.Implementation) *StorageCre
|
||||
return sc
|
||||
}
|
||||
|
||||
// SetTvPath sets the "tv_path" field.
|
||||
func (sc *StorageCreate) SetTvPath(s string) *StorageCreate {
|
||||
sc.mutation.SetTvPath(s)
|
||||
return sc
|
||||
}
|
||||
|
||||
// SetNillableTvPath sets the "tv_path" field if the given value is not nil.
|
||||
func (sc *StorageCreate) SetNillableTvPath(s *string) *StorageCreate {
|
||||
if s != nil {
|
||||
sc.SetTvPath(*s)
|
||||
}
|
||||
return sc
|
||||
}
|
||||
|
||||
// SetMoviePath sets the "movie_path" field.
|
||||
func (sc *StorageCreate) SetMoviePath(s string) *StorageCreate {
|
||||
sc.mutation.SetMoviePath(s)
|
||||
return sc
|
||||
}
|
||||
|
||||
// SetNillableMoviePath sets the "movie_path" field if the given value is not nil.
|
||||
func (sc *StorageCreate) SetNillableMoviePath(s *string) *StorageCreate {
|
||||
if s != nil {
|
||||
sc.SetMoviePath(*s)
|
||||
}
|
||||
return sc
|
||||
}
|
||||
|
||||
// SetSettings sets the "settings" field.
|
||||
func (sc *StorageCreate) SetSettings(s string) *StorageCreate {
|
||||
sc.mutation.SetSettings(s)
|
||||
@@ -171,6 +199,14 @@ func (sc *StorageCreate) createSpec() (*Storage, *sqlgraph.CreateSpec) {
|
||||
_spec.SetField(storage.FieldImplementation, field.TypeEnum, value)
|
||||
_node.Implementation = value
|
||||
}
|
||||
if value, ok := sc.mutation.TvPath(); ok {
|
||||
_spec.SetField(storage.FieldTvPath, field.TypeString, value)
|
||||
_node.TvPath = value
|
||||
}
|
||||
if value, ok := sc.mutation.MoviePath(); ok {
|
||||
_spec.SetField(storage.FieldMoviePath, field.TypeString, value)
|
||||
_node.MoviePath = value
|
||||
}
|
||||
if value, ok := sc.mutation.Settings(); ok {
|
||||
_spec.SetField(storage.FieldSettings, field.TypeString, value)
|
||||
_node.Settings = value
|
||||
|
||||
@@ -55,6 +55,46 @@ func (su *StorageUpdate) SetNillableImplementation(s *storage.Implementation) *S
|
||||
return su
|
||||
}
|
||||
|
||||
// SetTvPath sets the "tv_path" field.
|
||||
func (su *StorageUpdate) SetTvPath(s string) *StorageUpdate {
|
||||
su.mutation.SetTvPath(s)
|
||||
return su
|
||||
}
|
||||
|
||||
// SetNillableTvPath sets the "tv_path" field if the given value is not nil.
|
||||
func (su *StorageUpdate) SetNillableTvPath(s *string) *StorageUpdate {
|
||||
if s != nil {
|
||||
su.SetTvPath(*s)
|
||||
}
|
||||
return su
|
||||
}
|
||||
|
||||
// ClearTvPath clears the value of the "tv_path" field.
|
||||
func (su *StorageUpdate) ClearTvPath() *StorageUpdate {
|
||||
su.mutation.ClearTvPath()
|
||||
return su
|
||||
}
|
||||
|
||||
// SetMoviePath sets the "movie_path" field.
|
||||
func (su *StorageUpdate) SetMoviePath(s string) *StorageUpdate {
|
||||
su.mutation.SetMoviePath(s)
|
||||
return su
|
||||
}
|
||||
|
||||
// SetNillableMoviePath sets the "movie_path" field if the given value is not nil.
|
||||
func (su *StorageUpdate) SetNillableMoviePath(s *string) *StorageUpdate {
|
||||
if s != nil {
|
||||
su.SetMoviePath(*s)
|
||||
}
|
||||
return su
|
||||
}
|
||||
|
||||
// ClearMoviePath clears the value of the "movie_path" field.
|
||||
func (su *StorageUpdate) ClearMoviePath() *StorageUpdate {
|
||||
su.mutation.ClearMoviePath()
|
||||
return su
|
||||
}
|
||||
|
||||
// SetSettings sets the "settings" field.
|
||||
func (su *StorageUpdate) SetSettings(s string) *StorageUpdate {
|
||||
su.mutation.SetSettings(s)
|
||||
@@ -163,6 +203,18 @@ func (su *StorageUpdate) sqlSave(ctx context.Context) (n int, err error) {
|
||||
if value, ok := su.mutation.Implementation(); ok {
|
||||
_spec.SetField(storage.FieldImplementation, field.TypeEnum, value)
|
||||
}
|
||||
if value, ok := su.mutation.TvPath(); ok {
|
||||
_spec.SetField(storage.FieldTvPath, field.TypeString, value)
|
||||
}
|
||||
if su.mutation.TvPathCleared() {
|
||||
_spec.ClearField(storage.FieldTvPath, field.TypeString)
|
||||
}
|
||||
if value, ok := su.mutation.MoviePath(); ok {
|
||||
_spec.SetField(storage.FieldMoviePath, field.TypeString, value)
|
||||
}
|
||||
if su.mutation.MoviePathCleared() {
|
||||
_spec.ClearField(storage.FieldMoviePath, field.TypeString)
|
||||
}
|
||||
if value, ok := su.mutation.Settings(); ok {
|
||||
_spec.SetField(storage.FieldSettings, field.TypeString, value)
|
||||
}
|
||||
@@ -223,6 +275,46 @@ func (suo *StorageUpdateOne) SetNillableImplementation(s *storage.Implementation
|
||||
return suo
|
||||
}
|
||||
|
||||
// SetTvPath sets the "tv_path" field.
|
||||
func (suo *StorageUpdateOne) SetTvPath(s string) *StorageUpdateOne {
|
||||
suo.mutation.SetTvPath(s)
|
||||
return suo
|
||||
}
|
||||
|
||||
// SetNillableTvPath sets the "tv_path" field if the given value is not nil.
|
||||
func (suo *StorageUpdateOne) SetNillableTvPath(s *string) *StorageUpdateOne {
|
||||
if s != nil {
|
||||
suo.SetTvPath(*s)
|
||||
}
|
||||
return suo
|
||||
}
|
||||
|
||||
// ClearTvPath clears the value of the "tv_path" field.
|
||||
func (suo *StorageUpdateOne) ClearTvPath() *StorageUpdateOne {
|
||||
suo.mutation.ClearTvPath()
|
||||
return suo
|
||||
}
|
||||
|
||||
// SetMoviePath sets the "movie_path" field.
|
||||
func (suo *StorageUpdateOne) SetMoviePath(s string) *StorageUpdateOne {
|
||||
suo.mutation.SetMoviePath(s)
|
||||
return suo
|
||||
}
|
||||
|
||||
// SetNillableMoviePath sets the "movie_path" field if the given value is not nil.
|
||||
func (suo *StorageUpdateOne) SetNillableMoviePath(s *string) *StorageUpdateOne {
|
||||
if s != nil {
|
||||
suo.SetMoviePath(*s)
|
||||
}
|
||||
return suo
|
||||
}
|
||||
|
||||
// ClearMoviePath clears the value of the "movie_path" field.
|
||||
func (suo *StorageUpdateOne) ClearMoviePath() *StorageUpdateOne {
|
||||
suo.mutation.ClearMoviePath()
|
||||
return suo
|
||||
}
|
||||
|
||||
// SetSettings sets the "settings" field.
|
||||
func (suo *StorageUpdateOne) SetSettings(s string) *StorageUpdateOne {
|
||||
suo.mutation.SetSettings(s)
|
||||
@@ -361,6 +453,18 @@ func (suo *StorageUpdateOne) sqlSave(ctx context.Context) (_node *Storage, err e
|
||||
if value, ok := suo.mutation.Implementation(); ok {
|
||||
_spec.SetField(storage.FieldImplementation, field.TypeEnum, value)
|
||||
}
|
||||
if value, ok := suo.mutation.TvPath(); ok {
|
||||
_spec.SetField(storage.FieldTvPath, field.TypeString, value)
|
||||
}
|
||||
if suo.mutation.TvPathCleared() {
|
||||
_spec.ClearField(storage.FieldTvPath, field.TypeString)
|
||||
}
|
||||
if value, ok := suo.mutation.MoviePath(); ok {
|
||||
_spec.SetField(storage.FieldMoviePath, field.TypeString, value)
|
||||
}
|
||||
if suo.mutation.MoviePathCleared() {
|
||||
_spec.ClearField(storage.FieldMoviePath, field.TypeString)
|
||||
}
|
||||
if value, ok := suo.mutation.Settings(); ok {
|
||||
_spec.SetField(storage.FieldSettings, field.TypeString, value)
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ type Storage interface {
|
||||
Move(src, dest string) error
|
||||
Copy(src, dest string) error
|
||||
ReadDir(dir string) ([]fs.FileInfo, error)
|
||||
ReadFile(string)([]byte, error)
|
||||
ReadFile(string) ([]byte, error)
|
||||
WriteFile(string, []byte) error
|
||||
}
|
||||
|
||||
@@ -42,7 +42,6 @@ func (l *LocalStorage) Copy(src, destDir string) error {
|
||||
}
|
||||
log.Debugf("local storage target base dir is: %v", targetBase)
|
||||
|
||||
|
||||
err = filepath.Walk(src, func(path string, info fs.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -57,7 +56,7 @@ func (l *LocalStorage) Copy(src, destDir string) error {
|
||||
os.Mkdir(destName, os.ModePerm)
|
||||
} else { //is file
|
||||
if err := os.Link(path, destName); err != nil {
|
||||
log.Warnf("hard file error, will try copy file, source: %s, dest: %s", path, destName)
|
||||
log.Warnf("hard link file error: %v, will try copy file, source: %s, dest: %s", err, path, destName)
|
||||
if writer, err := os.OpenFile(destName, os.O_RDWR|os.O_CREATE|os.O_TRUNC, os.ModePerm); err != nil {
|
||||
return errors.Wrapf(err, "create file %s", destName)
|
||||
} else {
|
||||
@@ -99,7 +98,6 @@ func (l *LocalStorage) ReadFile(name string) ([]byte, error) {
|
||||
return os.ReadFile(filepath.Join(l.dir, name))
|
||||
}
|
||||
|
||||
|
||||
func (l *LocalStorage) WriteFile(name string, data []byte) error {
|
||||
func (l *LocalStorage) WriteFile(name string, data []byte) error {
|
||||
return os.WriteFile(filepath.Join(l.dir, name), data, os.ModePerm)
|
||||
}
|
||||
@@ -54,13 +54,13 @@ func (s *Server) downloadSeasonPackage(r1 torznab.Result, seriesId, seasonNum in
|
||||
dir := fmt.Sprintf("%s/Season %02d/", series.TargetDir, seasonNum)
|
||||
|
||||
history, err := s.db.SaveHistoryRecord(ent.History{
|
||||
MediaID: seriesId,
|
||||
EpisodeID: 0,
|
||||
SourceTitle: r1.Name,
|
||||
TargetDir: dir,
|
||||
Status: history.StatusRunning,
|
||||
Size: r1.Size,
|
||||
Saved: torrent.Save(),
|
||||
MediaID: seriesId,
|
||||
EpisodeID: 0,
|
||||
SourceTitle: r1.Name,
|
||||
TargetDir: dir,
|
||||
Status: history.StatusRunning,
|
||||
Size: r1.Size,
|
||||
Saved: torrent.Save(),
|
||||
DownloadClientID: dlClient.ID,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -102,13 +102,13 @@ func (s *Server) downloadEpisodeTorrent(r1 torznab.Result, seriesId, seasonNum,
|
||||
dir := fmt.Sprintf("%s/Season %02d/", series.TargetDir, seasonNum)
|
||||
|
||||
history, err := s.db.SaveHistoryRecord(ent.History{
|
||||
MediaID: ep.MediaID,
|
||||
EpisodeID: ep.ID,
|
||||
SourceTitle: r1.Name,
|
||||
TargetDir: dir,
|
||||
Status: history.StatusRunning,
|
||||
Size: r1.Size,
|
||||
Saved: torrent.Save(),
|
||||
MediaID: ep.MediaID,
|
||||
EpisodeID: ep.ID,
|
||||
SourceTitle: r1.Name,
|
||||
TargetDir: dir,
|
||||
Status: history.StatusRunning,
|
||||
Size: r1.Size,
|
||||
Saved: torrent.Save(),
|
||||
DownloadClientID: dlc.ID,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -265,44 +265,46 @@ func (s *Server) DownloadTorrent(c *gin.Context) (interface{}, error) {
|
||||
}
|
||||
res := torznab.Result{Name: name, Link: in.Link, Size: in.Size}
|
||||
return s.downloadEpisodeTorrent(res, in.MediaID, in.Season, in.Episode)
|
||||
}
|
||||
trc, dlc, err := s.getDownloadClient()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "connect transmission")
|
||||
}
|
||||
|
||||
torrent, err := trc.Download(in.Link, s.db.GetDownloadDir())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "downloading")
|
||||
}
|
||||
torrent.Start()
|
||||
name := in.Name
|
||||
if name == "" {
|
||||
name = m.OriginalName
|
||||
}
|
||||
go func() {
|
||||
ep, _ := s.db.GetMovieDummyEpisode(m.ID)
|
||||
history, err := s.db.SaveHistoryRecord(ent.History{
|
||||
MediaID: m.ID,
|
||||
EpisodeID: ep.ID,
|
||||
SourceTitle: name,
|
||||
TargetDir: m.TargetDir,
|
||||
Status: history.StatusRunning,
|
||||
Size: in.Size,
|
||||
Saved: torrent.Save(),
|
||||
DownloadClientID: dlc.ID,
|
||||
})
|
||||
} else {
|
||||
//movie
|
||||
trc, dlc, err := s.getDownloadClient()
|
||||
if err != nil {
|
||||
log.Errorf("save history error: %v", err)
|
||||
return nil, errors.Wrap(err, "connect transmission")
|
||||
}
|
||||
|
||||
s.tasks[history.ID] = &Task{Torrent: torrent}
|
||||
torrent, err := trc.Download(in.Link, s.db.GetDownloadDir())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "downloading")
|
||||
}
|
||||
torrent.Start()
|
||||
name := in.Name
|
||||
if name == "" {
|
||||
name = m.OriginalName
|
||||
}
|
||||
go func() {
|
||||
ep, _ := s.db.GetMovieDummyEpisode(m.ID)
|
||||
history, err := s.db.SaveHistoryRecord(ent.History{
|
||||
MediaID: m.ID,
|
||||
EpisodeID: ep.ID,
|
||||
SourceTitle: name,
|
||||
TargetDir: m.TargetDir,
|
||||
Status: history.StatusRunning,
|
||||
Size: in.Size,
|
||||
Saved: torrent.Save(),
|
||||
DownloadClientID: dlc.ID,
|
||||
})
|
||||
if err != nil {
|
||||
log.Errorf("save history error: %v", err)
|
||||
}
|
||||
|
||||
s.db.SetEpisodeStatus(ep.ID, episode.StatusDownloading)
|
||||
}()
|
||||
s.tasks[history.ID] = &Task{Torrent: torrent}
|
||||
|
||||
s.sendMsg(fmt.Sprintf(message.BeginDownload, in.Name))
|
||||
log.Infof("success add %s to download task", in.Name)
|
||||
return in.Name, nil
|
||||
s.db.SetEpisodeStatus(ep.ID, episode.StatusDownloading)
|
||||
}()
|
||||
|
||||
s.sendMsg(fmt.Sprintf(message.BeginDownload, in.Name))
|
||||
log.Infof("success add %s to download task", in.Name)
|
||||
return in.Name, nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ func (s *Server) AddStorage(c *gin.Context) (interface{}, error) {
|
||||
if in.Implementation == "webdav" {
|
||||
//test webdav
|
||||
wd := in.ToWebDavSetting()
|
||||
st, err := storage.NewWebdavStorage(wd.URL, wd.User, wd.Password, wd.TvPath, false)
|
||||
st, err := storage.NewWebdavStorage(wd.URL, wd.User, wd.Password, in.TvPath, false)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "new webdav")
|
||||
}
|
||||
@@ -112,13 +112,14 @@ func (s *Server) SuggestedMovieFolderName(c *gin.Context) (interface{}, error) {
|
||||
|
||||
func (s *Server) getStorage(storageId int, mediaType media.MediaType) (storage.Storage, error) {
|
||||
st := s.db.GetStorage(storageId)
|
||||
targetPath := st.TvPath
|
||||
if mediaType == media.MediaTypeMovie {
|
||||
targetPath = st.MoviePath
|
||||
}
|
||||
|
||||
switch st.Implementation {
|
||||
case storage1.ImplementationLocal:
|
||||
ls := st.ToLocalSetting()
|
||||
targetPath := ls.TvPath
|
||||
if mediaType == media.MediaTypeMovie {
|
||||
targetPath = ls.MoviePath
|
||||
}
|
||||
|
||||
storageImpl1, err := storage.NewLocalStorage(targetPath)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "new local")
|
||||
@@ -127,11 +128,6 @@ func (s *Server) getStorage(storageId int, mediaType media.MediaType) (storage.S
|
||||
|
||||
case storage1.ImplementationWebdav:
|
||||
ws := st.ToWebDavSetting()
|
||||
targetPath := ws.TvPath
|
||||
if mediaType == media.MediaTypeMovie {
|
||||
targetPath = ws.MoviePath
|
||||
}
|
||||
|
||||
storageImpl1, err := storage.NewWebdavStorage(ws.URL, ws.User, ws.Password, targetPath, ws.ChangeFileHash == "true")
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "new webdav")
|
||||
|
||||
@@ -112,16 +112,16 @@ func (s *Server) AddTv2Watchlist(c *gin.Context) (interface{}, error) {
|
||||
}
|
||||
}
|
||||
r, err := s.db.AddMediaWatchlist(&ent.Media{
|
||||
TmdbID: int(detail.ID),
|
||||
MediaType: media.MediaTypeTv,
|
||||
NameCn: nameCn,
|
||||
NameEn: nameEn,
|
||||
OriginalName: detail.OriginalName,
|
||||
Overview: detail.Overview,
|
||||
AirDate: detail.FirstAirDate,
|
||||
Resolution: media.Resolution(in.Resolution),
|
||||
StorageID: in.StorageID,
|
||||
TargetDir: in.Folder,
|
||||
TmdbID: int(detail.ID),
|
||||
MediaType: media.MediaTypeTv,
|
||||
NameCn: nameCn,
|
||||
NameEn: nameEn,
|
||||
OriginalName: detail.OriginalName,
|
||||
Overview: detail.Overview,
|
||||
AirDate: detail.FirstAirDate,
|
||||
Resolution: media.Resolution(in.Resolution),
|
||||
StorageID: in.StorageID,
|
||||
TargetDir: in.Folder,
|
||||
DownloadHistoryEpisodes: in.DownloadHistoryEpisodes,
|
||||
}, epIds)
|
||||
if err != nil {
|
||||
@@ -304,6 +304,11 @@ func (s *Server) GetMovieWatchlist(c *gin.Context) (interface{}, error) {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
type MediaDetails struct {
|
||||
*db.MediaDetails
|
||||
Storage *ent.Storage `json:"storage"`
|
||||
}
|
||||
|
||||
func (s *Server) GetMediaDetails(c *gin.Context) (interface{}, error) {
|
||||
ids := c.Param("id")
|
||||
id, err := strconv.Atoi(ids)
|
||||
@@ -311,7 +316,8 @@ func (s *Server) GetMediaDetails(c *gin.Context) (interface{}, error) {
|
||||
return nil, errors.Wrap(err, "convert")
|
||||
}
|
||||
detail := s.db.GetMediaDetails(id)
|
||||
return detail, nil
|
||||
st := s.db.GetStorage(detail.StorageID)
|
||||
return MediaDetails{MediaDetails: detail, Storage: &st.Storage}, nil
|
||||
}
|
||||
|
||||
func (s *Server) GetAvailableResolutions(c *gin.Context) (interface{}, error) {
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:ui/providers/APIs.dart';
|
||||
import 'package:ui/providers/activity.dart';
|
||||
import 'package:ui/providers/series_details.dart';
|
||||
import 'package:ui/providers/settings.dart';
|
||||
import 'package:ui/welcome_page.dart';
|
||||
import 'package:ui/widgets/detail_card.dart';
|
||||
import 'package:ui/widgets/utils.dart';
|
||||
import 'package:ui/widgets/progress_indicator.dart';
|
||||
import 'package:ui/widgets/widgets.dart';
|
||||
@@ -31,104 +28,12 @@ class _MovieDetailsPageState extends ConsumerState<MovieDetailsPage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var seriesDetails = ref.watch(mediaDetailsProvider(widget.id));
|
||||
var storage = ref.watch(storageSettingProvider);
|
||||
|
||||
return seriesDetails.when(
|
||||
data: (details) {
|
||||
return ListView(
|
||||
children: [
|
||||
Card(
|
||||
margin: const EdgeInsets.all(4),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
fit: BoxFit.cover,
|
||||
opacity: 0.3,
|
||||
colorFilter: ColorFilter.mode(
|
||||
Colors.black.withOpacity(0.3),
|
||||
BlendMode.dstATop),
|
||||
image: NetworkImage(
|
||||
"${APIs.imagesUrl}/${details.id}/backdrop.jpg",
|
||||
))),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
flex: 1,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: Image.network(
|
||||
"${APIs.imagesUrl}/${details.id}/poster.jpg",
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 6,
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Text("${details.resolution}"),
|
||||
const SizedBox(
|
||||
width: 30,
|
||||
),
|
||||
storage.when(
|
||||
data: (value) {
|
||||
for (final s in value) {
|
||||
if (s.id == details.storageId) {
|
||||
return Text(
|
||||
"${s.name}(${s.implementation})");
|
||||
}
|
||||
}
|
||||
return const Text("未知存储");
|
||||
},
|
||||
error: (error, stackTrace) =>
|
||||
Text("$error"),
|
||||
loading: () =>
|
||||
const MyProgressIndicator()),
|
||||
],
|
||||
),
|
||||
const Divider(thickness: 1, height: 1),
|
||||
Text(
|
||||
"${details.name} (${details.airDate!.split("-")[0]})",
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
const Text(""),
|
||||
Text(
|
||||
details.overview??"",
|
||||
),
|
||||
],
|
||||
)),
|
||||
Column(
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
var f = ref
|
||||
.read(mediaDetailsProvider(
|
||||
widget.id)
|
||||
.notifier)
|
||||
.delete().then((v) => context.go(WelcomePage.routeMoivie));
|
||||
showLoadingWithFuture(f);
|
||||
},
|
||||
icon: const Icon(Icons.delete))
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)),
|
||||
),
|
||||
DetailCard(details: details),
|
||||
NestedTabBar(
|
||||
id: widget.id,
|
||||
)
|
||||
@@ -157,7 +62,7 @@ class _NestedTabBarState extends ConsumerState<NestedTabBar>
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_nestedTabController = new TabController(length: 2, vsync: this);
|
||||
_nestedTabController = TabController(length: 2, vsync: this);
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -3,6 +3,7 @@ import 'dart:async';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:ui/providers/APIs.dart';
|
||||
import 'package:ui/providers/server_response.dart';
|
||||
import 'package:ui/providers/settings.dart';
|
||||
|
||||
var mediaDetailsProvider = AsyncNotifierProvider.autoDispose
|
||||
.family<SeriesDetailData, SeriesDetails, String>(SeriesDetailData.new);
|
||||
@@ -61,6 +62,8 @@ class SeriesDetails {
|
||||
String? resolution;
|
||||
int? storageId;
|
||||
String? airDate;
|
||||
String? mediaType;
|
||||
Storage? storage;
|
||||
|
||||
SeriesDetails(
|
||||
{this.id,
|
||||
@@ -73,7 +76,9 @@ class SeriesDetails {
|
||||
this.resolution,
|
||||
this.storageId,
|
||||
this.airDate,
|
||||
this.episodes});
|
||||
this.episodes,
|
||||
this.mediaType,
|
||||
this.storage});
|
||||
|
||||
SeriesDetails.fromJson(Map<String, dynamic> json) {
|
||||
id = json['id'];
|
||||
@@ -86,6 +91,8 @@ class SeriesDetails {
|
||||
resolution = json["resolution"];
|
||||
storageId = json["storage_id"];
|
||||
airDate = json["air_date"];
|
||||
mediaType = json["media_type"];
|
||||
storage = Storage.fromJson(json["storage"]);
|
||||
if (json['episodes'] != null) {
|
||||
episodes = <Episodes>[];
|
||||
json['episodes'].forEach((v) {
|
||||
@@ -146,14 +153,12 @@ var mediaTorrentsDataProvider = AsyncNotifierProvider.autoDispose
|
||||
// }
|
||||
// }
|
||||
|
||||
typedef TorrentQuery =({String mediaId, int seasonNumber, int episodeNumber});
|
||||
typedef TorrentQuery = ({String mediaId, int seasonNumber, int episodeNumber});
|
||||
|
||||
class MediaTorrentResource extends AutoDisposeFamilyAsyncNotifier<
|
||||
List<TorrentResource>, TorrentQuery> {
|
||||
|
||||
@override
|
||||
FutureOr<List<TorrentResource>> build(TorrentQuery arg) async {
|
||||
|
||||
final dio = await APIs.getDio();
|
||||
var resp = await dio.post(APIs.availableTorrentsUrl, data: {
|
||||
"id": int.parse(arg.mediaId),
|
||||
|
||||
@@ -283,6 +283,8 @@ class Storage {
|
||||
this.id,
|
||||
this.name,
|
||||
this.implementation,
|
||||
this.tvPath,
|
||||
this.moviePath,
|
||||
this.settings,
|
||||
this.isDefault,
|
||||
});
|
||||
@@ -290,6 +292,8 @@ class Storage {
|
||||
final int? id;
|
||||
final String? name;
|
||||
final String? implementation;
|
||||
final String? tvPath;
|
||||
final String? moviePath;
|
||||
final Map<String, dynamic>? settings;
|
||||
final bool? isDefault;
|
||||
|
||||
@@ -298,6 +302,8 @@ class Storage {
|
||||
id: json1["id"],
|
||||
name: json1["name"],
|
||||
implementation: json1["implementation"],
|
||||
tvPath: json1["tv_path"],
|
||||
moviePath: json1["movie_path"],
|
||||
settings: json.decode(json1["settings"]),
|
||||
isDefault: json1["default"]);
|
||||
}
|
||||
@@ -306,6 +312,8 @@ class Storage {
|
||||
"id": id,
|
||||
"name": name,
|
||||
"implementation": implementation,
|
||||
"tv_path": tvPath,
|
||||
"movie_path": moviePath,
|
||||
"settings": settings,
|
||||
"default": isDefault,
|
||||
};
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
@@ -59,7 +59,7 @@ class _GeneralState extends ConsumerState<GeneralSettings> {
|
||||
name: "proxy",
|
||||
decoration: const InputDecoration(
|
||||
labelText: "代理地址",
|
||||
icon: Icon(Icons.folder),
|
||||
icon: Icon(Icons.web),
|
||||
helperText: "后台联网代理地址,留空表示不启用代理"),
|
||||
),
|
||||
SizedBox(
|
||||
|
||||
@@ -39,7 +39,7 @@ class _StorageState extends ConsumerState<StorageSettings> {
|
||||
loading: () => const MyProgressIndicator());
|
||||
}
|
||||
|
||||
Future<void> showStorageDetails(Storage s) {
|
||||
Future<void> showStorageDetails(Storage s) {
|
||||
final _formKey = GlobalKey<FormBuilderState>();
|
||||
|
||||
String selectImpl = s.implementation == null ? "local" : s.implementation!;
|
||||
@@ -53,10 +53,9 @@ class _StorageState extends ConsumerState<StorageSettings> {
|
||||
"impl": s.implementation == null ? "local" : s.implementation!,
|
||||
"user": s.settings != null ? s.settings!["user"] ?? "" : "",
|
||||
"password": s.settings != null ? s.settings!["password"] ?? "" : "",
|
||||
"tv_path": s.settings != null ? s.settings!["tv_path"] ?? "" : "",
|
||||
"tv_path": s.tvPath,
|
||||
"url": s.settings != null ? s.settings!["url"] ?? "" : "",
|
||||
"movie_path":
|
||||
s.settings != null ? s.settings!["movie_path"] ?? "" : "",
|
||||
"movie_path": s.moviePath,
|
||||
"change_file_hash": s.settings != null
|
||||
? s.settings!["change_file_hash"] == "true"
|
||||
? true
|
||||
@@ -147,9 +146,9 @@ class _StorageState extends ConsumerState<StorageSettings> {
|
||||
return ref.read(storageSettingProvider.notifier).addStorage(Storage(
|
||||
name: values["name"],
|
||||
implementation: selectImpl,
|
||||
tvPath: values["tv_path"],
|
||||
moviePath: values["movie_path"],
|
||||
settings: {
|
||||
"tv_path": values["tv_path"],
|
||||
"movie_path": values["movie_path"],
|
||||
"url": values["url"],
|
||||
"user": values["user"],
|
||||
"password": values["password"],
|
||||
@@ -168,7 +167,7 @@ class _StorageState extends ConsumerState<StorageSettings> {
|
||||
return ref.read(storageSettingProvider.notifier).deleteStorage(s.id!);
|
||||
}
|
||||
|
||||
return showSettingDialog(context,'存储', s.id != null, widgets, onSubmit, onDelete);
|
||||
return showSettingDialog(
|
||||
context, '存储', s.id != null, widgets, onSubmit, onDelete);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:ui/providers/APIs.dart';
|
||||
import 'package:ui/providers/series_details.dart';
|
||||
import 'package:ui/providers/settings.dart';
|
||||
import 'package:ui/welcome_page.dart';
|
||||
import 'package:ui/widgets/detail_card.dart';
|
||||
import 'package:ui/widgets/utils.dart';
|
||||
import 'package:ui/widgets/progress_indicator.dart';
|
||||
import 'package:ui/widgets/widgets.dart';
|
||||
@@ -35,7 +32,6 @@ class _TvDetailsPageState extends ConsumerState<TvDetailsPage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var seriesDetails = ref.watch(mediaDetailsProvider(widget.seriesId));
|
||||
var storage = ref.watch(storageSettingProvider);
|
||||
return seriesDetails.when(
|
||||
data: (details) {
|
||||
Map<int, List<DataRow>> m = {};
|
||||
@@ -143,95 +139,7 @@ class _TvDetailsPageState extends ConsumerState<TvDetailsPage> {
|
||||
}
|
||||
return ListView(
|
||||
children: [
|
||||
Card(
|
||||
margin: const EdgeInsets.all(4),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
fit: BoxFit.cover,
|
||||
opacity: 0.3,
|
||||
colorFilter: ColorFilter.mode(
|
||||
Colors.black.withOpacity(0.3), BlendMode.dstATop),
|
||||
image: NetworkImage(
|
||||
"${APIs.imagesUrl}/${details.id}/backdrop.jpg"))),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
flex: 1,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: Image.network(
|
||||
"${APIs.imagesUrl}/${details.id}/poster.jpg",
|
||||
fit: BoxFit.contain),
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
flex: 6,
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Text("${details.resolution}"),
|
||||
const SizedBox(
|
||||
width: 30,
|
||||
),
|
||||
storage.when(
|
||||
data: (value) {
|
||||
for (final s in value) {
|
||||
if (s.id == details.storageId) {
|
||||
return Text(
|
||||
"${s.name}(${s.implementation})");
|
||||
}
|
||||
}
|
||||
return const Text("未知存储");
|
||||
},
|
||||
error: (error, stackTrace) =>
|
||||
Text("$error"),
|
||||
loading: () => const Text("")),
|
||||
],
|
||||
),
|
||||
const Divider(thickness: 1, height: 1),
|
||||
Text(
|
||||
"${details.name} ${details.name != details.originalName ? details.originalName : ''} (${details.airDate!.split("-")[0]})",
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold),
|
||||
),
|
||||
const Text(""),
|
||||
Text(
|
||||
details.overview ?? "",
|
||||
),
|
||||
],
|
||||
)),
|
||||
Column(
|
||||
children: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
var f = ref
|
||||
.read(mediaDetailsProvider(
|
||||
widget.seriesId)
|
||||
.notifier)
|
||||
.delete().then((v) => context.go(WelcomePage.routeTv));
|
||||
showLoadingWithFuture(f);
|
||||
},
|
||||
icon: const Icon(Icons.delete))
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
DetailCard(details: details),
|
||||
Column(
|
||||
children: list,
|
||||
),
|
||||
|
||||
111
ui/lib/widgets/detail_card.dart
Normal file
111
ui/lib/widgets/detail_card.dart
Normal file
@@ -0,0 +1,111 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:ui/providers/APIs.dart';
|
||||
import 'package:ui/providers/series_details.dart';
|
||||
import 'package:ui/welcome_page.dart';
|
||||
|
||||
import 'widgets.dart';
|
||||
|
||||
class DetailCard extends ConsumerStatefulWidget {
|
||||
final SeriesDetails details;
|
||||
|
||||
const DetailCard({super.key, required this.details});
|
||||
|
||||
@override
|
||||
ConsumerState<ConsumerStatefulWidget> createState() {
|
||||
return _DetailCardState();
|
||||
}
|
||||
}
|
||||
|
||||
class _DetailCardState extends ConsumerState<DetailCard> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Card(
|
||||
margin: const EdgeInsets.all(4),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
child: Container(
|
||||
constraints: BoxConstraints(maxHeight: MediaQuery.of(context).size.height*0.4),
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
fit: BoxFit.cover,
|
||||
opacity: 0.3,
|
||||
colorFilter: ColorFilter.mode(
|
||||
Colors.black.withOpacity(0.3), BlendMode.dstATop),
|
||||
image: NetworkImage(
|
||||
"${APIs.imagesUrl}/${widget.details.id}/backdrop.jpg"))),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: Row(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
flex: 2,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: Image.network(
|
||||
"${APIs.imagesUrl}/${widget.details.id}/poster.jpg",
|
||||
fit: BoxFit.contain),
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
flex: 4,
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
const Text(""),
|
||||
Row(
|
||||
children: [
|
||||
Text("${widget.details.resolution}"),
|
||||
const SizedBox(
|
||||
width: 30,
|
||||
),
|
||||
Text(
|
||||
"${widget.details.storage!.name} (${widget.details.storage!.implementation})")
|
||||
],
|
||||
),
|
||||
const Divider(thickness: 1, height: 1),
|
||||
Text(
|
||||
"${widget.details.name} ${widget.details.name != widget.details.originalName ? widget.details.originalName : ''} (${widget.details.airDate!.split("-")[0]})",
|
||||
style: const TextStyle(
|
||||
fontSize: 20, fontWeight: FontWeight.bold),
|
||||
),
|
||||
const Text(""),
|
||||
Expanded(
|
||||
child: Text(
|
||||
widget.details.overview ?? "",
|
||||
)),
|
||||
Row(
|
||||
children: [
|
||||
deleteIcon(),
|
||||
],
|
||||
)
|
||||
],
|
||||
)),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget deleteIcon() {
|
||||
return IconButton(
|
||||
onPressed: () {
|
||||
var f = ref
|
||||
.read(mediaDetailsProvider(widget.details.id.toString()).notifier)
|
||||
.delete()
|
||||
.then((v) => context.go(widget.details.mediaType == "tv"
|
||||
? WelcomePage.routeTv
|
||||
: WelcomePage.routeMoivie));
|
||||
showLoadingWithFuture(f);
|
||||
},
|
||||
icon: const Icon(Icons.delete));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user