2019-02-09 12:30:49 +00:00
|
|
|
package api
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"sort"
|
|
|
|
"strconv"
|
2019-08-21 04:47:48 +00:00
|
|
|
|
2020-01-07 22:21:23 +00:00
|
|
|
"github.com/stashapp/stash/pkg/logger"
|
2019-08-21 04:47:48 +00:00
|
|
|
"github.com/stashapp/stash/pkg/models"
|
2021-06-11 07:24:58 +00:00
|
|
|
"github.com/stashapp/stash/pkg/plugin"
|
2019-02-09 12:30:49 +00:00
|
|
|
)
|
|
|
|
|
2021-06-11 07:24:58 +00:00
|
|
|
type hookExecutor interface {
|
|
|
|
ExecutePostHooks(ctx context.Context, id int, hookType plugin.HookTriggerEnum, input interface{}, inputFields []string)
|
|
|
|
}
|
|
|
|
|
2021-01-18 01:23:20 +00:00
|
|
|
type Resolver struct {
|
2021-06-11 07:24:58 +00:00
|
|
|
txnManager models.TransactionManager
|
|
|
|
hookExecutor hookExecutor
|
2021-01-18 01:23:20 +00:00
|
|
|
}
|
2019-02-09 12:30:49 +00:00
|
|
|
|
|
|
|
func (r *Resolver) Gallery() models.GalleryResolver {
|
|
|
|
return &galleryResolver{r}
|
|
|
|
}
|
|
|
|
func (r *Resolver) Mutation() models.MutationResolver {
|
|
|
|
return &mutationResolver{r}
|
|
|
|
}
|
|
|
|
func (r *Resolver) Performer() models.PerformerResolver {
|
|
|
|
return &performerResolver{r}
|
|
|
|
}
|
|
|
|
func (r *Resolver) Query() models.QueryResolver {
|
|
|
|
return &queryResolver{r}
|
|
|
|
}
|
|
|
|
func (r *Resolver) Scene() models.SceneResolver {
|
|
|
|
return &sceneResolver{r}
|
|
|
|
}
|
2020-10-12 23:12:46 +00:00
|
|
|
func (r *Resolver) Image() models.ImageResolver {
|
|
|
|
return &imageResolver{r}
|
|
|
|
}
|
2019-02-09 12:30:49 +00:00
|
|
|
func (r *Resolver) SceneMarker() models.SceneMarkerResolver {
|
|
|
|
return &sceneMarkerResolver{r}
|
|
|
|
}
|
|
|
|
func (r *Resolver) Studio() models.StudioResolver {
|
|
|
|
return &studioResolver{r}
|
|
|
|
}
|
2020-03-10 03:28:15 +00:00
|
|
|
func (r *Resolver) Movie() models.MovieResolver {
|
|
|
|
return &movieResolver{r}
|
|
|
|
}
|
2019-02-09 12:30:49 +00:00
|
|
|
func (r *Resolver) Subscription() models.SubscriptionResolver {
|
|
|
|
return &subscriptionResolver{r}
|
|
|
|
}
|
|
|
|
func (r *Resolver) Tag() models.TagResolver {
|
|
|
|
return &tagResolver{r}
|
|
|
|
}
|
|
|
|
|
|
|
|
type mutationResolver struct{ *Resolver }
|
|
|
|
type queryResolver struct{ *Resolver }
|
|
|
|
type subscriptionResolver struct{ *Resolver }
|
|
|
|
|
|
|
|
type galleryResolver struct{ *Resolver }
|
|
|
|
type performerResolver struct{ *Resolver }
|
|
|
|
type sceneResolver struct{ *Resolver }
|
|
|
|
type sceneMarkerResolver struct{ *Resolver }
|
2020-10-12 23:12:46 +00:00
|
|
|
type imageResolver struct{ *Resolver }
|
2019-02-09 12:30:49 +00:00
|
|
|
type studioResolver struct{ *Resolver }
|
2020-03-10 03:28:15 +00:00
|
|
|
type movieResolver struct{ *Resolver }
|
2019-02-09 12:30:49 +00:00
|
|
|
type tagResolver struct{ *Resolver }
|
|
|
|
|
2021-01-18 01:23:20 +00:00
|
|
|
func (r *Resolver) withTxn(ctx context.Context, fn func(r models.Repository) error) error {
|
|
|
|
return r.txnManager.WithTxn(ctx, fn)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *Resolver) withReadTxn(ctx context.Context, fn func(r models.ReaderRepository) error) error {
|
|
|
|
return r.txnManager.WithReadTxn(ctx, fn)
|
2019-02-09 12:30:49 +00:00
|
|
|
}
|
|
|
|
|
2021-01-18 01:23:20 +00:00
|
|
|
func (r *queryResolver) MarkerWall(ctx context.Context, q *string) (ret []*models.SceneMarker, err error) {
|
|
|
|
if err := r.withReadTxn(ctx, func(repo models.ReaderRepository) error {
|
|
|
|
ret, err = repo.SceneMarker().Wall(q)
|
|
|
|
return err
|
|
|
|
}); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return ret, nil
|
2019-02-09 12:30:49 +00:00
|
|
|
}
|
|
|
|
|
2021-01-18 01:23:20 +00:00
|
|
|
func (r *queryResolver) SceneWall(ctx context.Context, q *string) (ret []*models.Scene, err error) {
|
|
|
|
if err := r.withReadTxn(ctx, func(repo models.ReaderRepository) error {
|
|
|
|
ret, err = repo.Scene().Wall(q)
|
|
|
|
return err
|
|
|
|
}); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (r *queryResolver) MarkerStrings(ctx context.Context, q *string, sort *string) (ret []*models.MarkerStringsResultType, err error) {
|
|
|
|
if err := r.withReadTxn(ctx, func(repo models.ReaderRepository) error {
|
|
|
|
ret, err = repo.SceneMarker().GetMarkerStrings(q, sort)
|
|
|
|
return err
|
|
|
|
}); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret, nil
|
2019-02-09 12:30:49 +00:00
|
|
|
}
|
|
|
|
|
2019-03-26 15:35:06 +00:00
|
|
|
func (r *queryResolver) Stats(ctx context.Context) (*models.StatsResultType, error) {
|
2021-01-18 01:23:20 +00:00
|
|
|
var ret models.StatsResultType
|
|
|
|
if err := r.withReadTxn(ctx, func(repo models.ReaderRepository) error {
|
|
|
|
scenesQB := repo.Scene()
|
|
|
|
imageQB := repo.Image()
|
|
|
|
galleryQB := repo.Gallery()
|
|
|
|
studiosQB := repo.Studio()
|
|
|
|
performersQB := repo.Performer()
|
|
|
|
moviesQB := repo.Movie()
|
|
|
|
tagsQB := repo.Tag()
|
|
|
|
scenesCount, _ := scenesQB.Count()
|
|
|
|
scenesSize, _ := scenesQB.Size()
|
2021-08-26 03:37:08 +00:00
|
|
|
scenesDuration, _ := scenesQB.Duration()
|
2021-01-18 01:23:20 +00:00
|
|
|
imageCount, _ := imageQB.Count()
|
|
|
|
imageSize, _ := imageQB.Size()
|
|
|
|
galleryCount, _ := galleryQB.Count()
|
|
|
|
performersCount, _ := performersQB.Count()
|
|
|
|
studiosCount, _ := studiosQB.Count()
|
|
|
|
moviesCount, _ := moviesQB.Count()
|
|
|
|
tagsCount, _ := tagsQB.Count()
|
|
|
|
|
|
|
|
ret = models.StatsResultType{
|
|
|
|
SceneCount: scenesCount,
|
|
|
|
ScenesSize: scenesSize,
|
2021-08-26 03:37:08 +00:00
|
|
|
ScenesDuration: scenesDuration,
|
2021-01-18 01:23:20 +00:00
|
|
|
ImageCount: imageCount,
|
|
|
|
ImagesSize: imageSize,
|
|
|
|
GalleryCount: galleryCount,
|
|
|
|
PerformerCount: performersCount,
|
|
|
|
StudioCount: studiosCount,
|
|
|
|
MovieCount: moviesCount,
|
|
|
|
TagCount: tagsCount,
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &ret, nil
|
2019-02-09 12:30:49 +00:00
|
|
|
}
|
|
|
|
|
2019-08-21 04:47:48 +00:00
|
|
|
func (r *queryResolver) Version(ctx context.Context) (*models.Version, error) {
|
2019-11-17 21:41:08 +00:00
|
|
|
version, hash, buildtime := GetVersion()
|
2019-08-21 04:47:48 +00:00
|
|
|
|
|
|
|
return &models.Version{
|
2019-11-17 21:41:08 +00:00
|
|
|
Version: &version,
|
2019-08-21 04:47:48 +00:00
|
|
|
Hash: hash,
|
|
|
|
BuildTime: buildtime,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2020-01-07 22:21:23 +00:00
|
|
|
//Gets latest version (git shorthash commit for now)
|
|
|
|
func (r *queryResolver) Latestversion(ctx context.Context) (*models.ShortVersion, error) {
|
|
|
|
ver, url, err := GetLatestVersion(true)
|
|
|
|
if err == nil {
|
|
|
|
logger.Infof("Retrieved latest hash: %s", ver)
|
|
|
|
} else {
|
|
|
|
logger.Errorf("Error while retrieving latest hash: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return &models.ShortVersion{
|
|
|
|
Shorthash: ver,
|
|
|
|
URL: url,
|
|
|
|
}, err
|
|
|
|
}
|
|
|
|
|
2019-02-09 12:30:49 +00:00
|
|
|
// Get scene marker tags which show up under the video.
|
2019-05-27 19:34:26 +00:00
|
|
|
func (r *queryResolver) SceneMarkerTags(ctx context.Context, scene_id string) ([]*models.SceneMarkerTag, error) {
|
2021-01-18 01:23:20 +00:00
|
|
|
sceneID, err := strconv.Atoi(scene_id)
|
2019-02-09 12:30:49 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var keys []int
|
2021-01-18 01:23:20 +00:00
|
|
|
tags := make(map[int]*models.SceneMarkerTag)
|
|
|
|
|
|
|
|
if err := r.withReadTxn(ctx, func(repo models.ReaderRepository) error {
|
|
|
|
sceneMarkers, err := repo.SceneMarker().FindBySceneID(sceneID)
|
2019-02-09 12:30:49 +00:00
|
|
|
if err != nil {
|
2021-01-18 01:23:20 +00:00
|
|
|
return err
|
2019-02-09 12:30:49 +00:00
|
|
|
}
|
2021-01-18 01:23:20 +00:00
|
|
|
|
|
|
|
tqb := repo.Tag()
|
|
|
|
for _, sceneMarker := range sceneMarkers {
|
|
|
|
markerPrimaryTag, err := tqb.Find(sceneMarker.PrimaryTagID)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
_, hasKey := tags[markerPrimaryTag.ID]
|
|
|
|
if !hasKey {
|
2021-05-25 01:03:09 +00:00
|
|
|
sceneMarkerTag := &models.SceneMarkerTag{Tag: markerPrimaryTag}
|
2021-01-18 01:23:20 +00:00
|
|
|
tags[markerPrimaryTag.ID] = sceneMarkerTag
|
|
|
|
keys = append(keys, markerPrimaryTag.ID)
|
|
|
|
}
|
|
|
|
tags[markerPrimaryTag.ID].SceneMarkers = append(tags[markerPrimaryTag.ID].SceneMarkers, sceneMarker)
|
2019-02-09 12:30:49 +00:00
|
|
|
}
|
2021-01-18 01:23:20 +00:00
|
|
|
|
|
|
|
return nil
|
|
|
|
}); err != nil {
|
|
|
|
return nil, err
|
2019-02-09 12:30:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Sort so that primary tags that show up earlier in the video are first.
|
|
|
|
sort.Slice(keys, func(i, j int) bool {
|
|
|
|
a := tags[keys[i]]
|
|
|
|
b := tags[keys[j]]
|
|
|
|
return a.SceneMarkers[0].Seconds < b.SceneMarkers[0].Seconds
|
|
|
|
})
|
|
|
|
|
2019-05-27 19:34:26 +00:00
|
|
|
var result []*models.SceneMarkerTag
|
2019-02-09 12:30:49 +00:00
|
|
|
for _, key := range keys {
|
2019-05-27 19:34:26 +00:00
|
|
|
result = append(result, tags[key])
|
2019-02-09 12:30:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return result, nil
|
|
|
|
}
|