File storage rewrite (#2676)

* Restructure data layer part 2 (#2599)
* Refactor and separate image model
* Refactor image query builder
* Handle relationships in image query builder
* Remove relationship management methods
* Refactor gallery model/query builder
* Add scenes to gallery model
* Convert scene model
* Refactor scene models
* Remove unused methods
* Add unit tests for gallery
* Add image tests
* Add scene tests
* Convert unnecessary scene value pointers to values
* Convert unnecessary pointer values to values
* Refactor scene partial
* Add scene partial tests
* Refactor ImagePartial
* Add image partial tests
* Refactor gallery partial update
* Add partial gallery update tests
* Use zero/null package for null values
* Add files and scan system
* Add sqlite implementation for files/folders
* Add unit tests for files/folders
* Image refactors
* Update image data layer
* Refactor gallery model and creation
* Refactor scene model
* Refactor scenes
* Don't set title from filename
* Allow galleries to freely add/remove images
* Add multiple scene file support to graphql and UI
* Add multiple file support for images in graphql/UI
* Add multiple file for galleries in graphql/UI
* Remove use of some deprecated fields
* Remove scene path usage
* Remove gallery path usage
* Remove path from image
* Move funscript to video file
* Refactor caption detection
* Migrate existing data
* Add post commit/rollback hook system
* Lint. Comment out import/export tests
* Add WithDatabase read only wrapper
* Prepend tasks to list
* Add 32 pre-migration
* Add warnings in release and migration notes
This commit is contained in:
WithoutPants
2022-07-13 16:30:54 +10:00
parent 30877c75fb
commit 5495d72849
359 changed files with 43690 additions and 16000 deletions

View File

@@ -15,13 +15,8 @@ import (
"github.com/stashapp/stash/pkg/utils"
)
type CoverStashIDGetter interface {
type CoverGetter interface {
GetCover(ctx context.Context, sceneID int) ([]byte, error)
GetStashIDs(ctx context.Context, sceneID int) ([]*models.StashID, error)
}
type MovieGetter interface {
GetMovies(ctx context.Context, sceneID int) ([]models.MoviesScenes, error)
}
type MarkerTagFinder interface {
@@ -41,47 +36,38 @@ type TagFinder interface {
// ToBasicJSON converts a scene object into its JSON object equivalent. It
// does not convert the relationships to other objects, with the exception
// of cover image.
func ToBasicJSON(ctx context.Context, reader CoverStashIDGetter, scene *models.Scene) (*jsonschema.Scene, error) {
func ToBasicJSON(ctx context.Context, reader CoverGetter, scene *models.Scene) (*jsonschema.Scene, error) {
newSceneJSON := jsonschema.Scene{
CreatedAt: json.JSONTime{Time: scene.CreatedAt.Timestamp},
UpdatedAt: json.JSONTime{Time: scene.UpdatedAt.Timestamp},
Title: scene.Title,
URL: scene.URL,
Details: scene.Details,
CreatedAt: json.JSONTime{Time: scene.CreatedAt},
UpdatedAt: json.JSONTime{Time: scene.UpdatedAt},
}
if scene.Checksum.Valid {
newSceneJSON.Checksum = scene.Checksum.String
// if scene.Checksum != nil {
// newSceneJSON.Checksum = *scene.Checksum
// }
// if scene.OSHash != nil {
// newSceneJSON.OSHash = *scene.OSHash
// }
// if scene.Phash != nil {
// newSceneJSON.Phash = utils.PhashToString(*scene.Phash)
// }
if scene.Date != nil {
newSceneJSON.Date = scene.Date.String()
}
if scene.OSHash.Valid {
newSceneJSON.OSHash = scene.OSHash.String
}
if scene.Phash.Valid {
newSceneJSON.Phash = utils.PhashToString(scene.Phash.Int64)
}
if scene.Title.Valid {
newSceneJSON.Title = scene.Title.String
}
if scene.URL.Valid {
newSceneJSON.URL = scene.URL.String
}
if scene.Date.Valid {
newSceneJSON.Date = utils.GetYMDFromDatabaseDate(scene.Date.String)
}
if scene.Rating.Valid {
newSceneJSON.Rating = int(scene.Rating.Int64)
if scene.Rating != nil {
newSceneJSON.Rating = *scene.Rating
}
newSceneJSON.Organized = scene.Organized
newSceneJSON.OCounter = scene.OCounter
if scene.Details.Valid {
newSceneJSON.Details = scene.Details.String
}
newSceneJSON.File = getSceneFileJSON(scene)
cover, err := reader.GetCover(ctx, scene.ID)
@@ -93,9 +79,8 @@ func ToBasicJSON(ctx context.Context, reader CoverStashIDGetter, scene *models.S
newSceneJSON.Cover = utils.GetBase64StringFromData(cover)
}
stashIDs, _ := reader.GetStashIDs(ctx, scene.ID)
var ret []models.StashID
for _, stashID := range stashIDs {
for _, stashID := range scene.StashIDs {
newJoin := models.StashID{
StashID: stashID.StashID,
Endpoint: stashID.Endpoint,
@@ -111,45 +96,46 @@ func ToBasicJSON(ctx context.Context, reader CoverStashIDGetter, scene *models.S
func getSceneFileJSON(scene *models.Scene) *jsonschema.SceneFile {
ret := &jsonschema.SceneFile{}
if scene.FileModTime.Valid {
ret.ModTime = json.JSONTime{Time: scene.FileModTime.Timestamp}
}
// TODO
// if scene.FileModTime != nil {
// ret.ModTime = json.JSONTime{Time: *scene.FileModTime}
// }
if scene.Size.Valid {
ret.Size = scene.Size.String
}
// if scene.Size != nil {
// ret.Size = *scene.Size
// }
if scene.Duration.Valid {
ret.Duration = getDecimalString(scene.Duration.Float64)
}
// if scene.Duration != nil {
// ret.Duration = getDecimalString(*scene.Duration)
// }
if scene.VideoCodec.Valid {
ret.VideoCodec = scene.VideoCodec.String
}
// if scene.VideoCodec != nil {
// ret.VideoCodec = *scene.VideoCodec
// }
if scene.AudioCodec.Valid {
ret.AudioCodec = scene.AudioCodec.String
}
// if scene.AudioCodec != nil {
// ret.AudioCodec = *scene.AudioCodec
// }
if scene.Format.Valid {
ret.Format = scene.Format.String
}
// if scene.Format != nil {
// ret.Format = *scene.Format
// }
if scene.Width.Valid {
ret.Width = int(scene.Width.Int64)
}
// if scene.Width != nil {
// ret.Width = *scene.Width
// }
if scene.Height.Valid {
ret.Height = int(scene.Height.Int64)
}
// if scene.Height != nil {
// ret.Height = *scene.Height
// }
if scene.Framerate.Valid {
ret.Framerate = getDecimalString(scene.Framerate.Float64)
}
// if scene.Framerate != nil {
// ret.Framerate = getDecimalString(*scene.Framerate)
// }
if scene.Bitrate.Valid {
ret.Bitrate = int(scene.Bitrate.Int64)
}
// if scene.Bitrate != nil {
// ret.Bitrate = int(*scene.Bitrate)
// }
return ret
}
@@ -157,8 +143,8 @@ func getSceneFileJSON(scene *models.Scene) *jsonschema.SceneFile {
// GetStudioName returns the name of the provided scene's studio. It returns an
// empty string if there is no studio assigned to the scene.
func GetStudioName(ctx context.Context, reader studio.Finder, scene *models.Scene) (string, error) {
if scene.StudioID.Valid {
studio, err := reader.Find(ctx, int(scene.StudioID.Int64))
if scene.StudioID != nil {
studio, err := reader.Find(ctx, *scene.StudioID)
if err != nil {
return "", err
}
@@ -232,11 +218,8 @@ type MovieFinder interface {
// GetSceneMoviesJSON returns a slice of SceneMovie JSON representation objects
// corresponding to the provided scene's scene movie relationships.
func GetSceneMoviesJSON(ctx context.Context, movieReader MovieFinder, sceneReader MovieGetter, scene *models.Scene) ([]jsonschema.SceneMovie, error) {
sceneMovies, err := sceneReader.GetMovies(ctx, scene.ID)
if err != nil {
return nil, fmt.Errorf("error getting scene movies: %v", err)
}
func GetSceneMoviesJSON(ctx context.Context, movieReader MovieFinder, scene *models.Scene) ([]jsonschema.SceneMovie, error) {
sceneMovies := scene.Movies
var results []jsonschema.SceneMovie
for _, sceneMovie := range sceneMovies {
@@ -247,8 +230,10 @@ func GetSceneMoviesJSON(ctx context.Context, movieReader MovieFinder, sceneReade
if movie.Name.Valid {
sceneMovieJSON := jsonschema.SceneMovie{
MovieName: movie.Name.String,
SceneIndex: int(sceneMovie.SceneIndex.Int64),
MovieName: movie.Name.String,
}
if sceneMovie.SceneIndex != nil {
sceneMovieJSON.SceneIndex = *sceneMovie.SceneIndex
}
results = append(results, sceneMovieJSON)
}
@@ -258,14 +243,10 @@ func GetSceneMoviesJSON(ctx context.Context, movieReader MovieFinder, sceneReade
}
// GetDependentMovieIDs returns a slice of movie IDs that this scene references.
func GetDependentMovieIDs(ctx context.Context, sceneReader MovieGetter, scene *models.Scene) ([]int, error) {
func GetDependentMovieIDs(ctx context.Context, scene *models.Scene) ([]int, error) {
var ret []int
m, err := sceneReader.GetMovies(ctx, scene.ID)
if err != nil {
return nil, err
}
m := scene.Movies
for _, mm := range m {
ret = append(ret, mm.MovieID)
}