mirror of
https://github.com/stashapp/stash.git
synced 2025-12-18 04:44:37 +03:00
Moved everything out of internal
This commit is contained in:
8
api/api-packr.go
Normal file
8
api/api-packr.go
Normal file
@@ -0,0 +1,8 @@
|
||||
// +build !skippackr
|
||||
// Code generated by github.com/gobuffalo/packr/v2. DO NOT EDIT.
|
||||
|
||||
// You can use the "packr clean" command to clean up this,
|
||||
// and any other packr generated files.
|
||||
package api
|
||||
|
||||
import _ "github.com/stashapp/stash/packrd"
|
||||
156
api/resolver.go
Normal file
156
api/resolver.go
Normal file
@@ -0,0 +1,156 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/stashapp/stash/models"
|
||||
"github.com/stashapp/stash/scraper"
|
||||
"sort"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type Resolver struct{}
|
||||
|
||||
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}
|
||||
}
|
||||
func (r *Resolver) SceneMarker() models.SceneMarkerResolver {
|
||||
return &sceneMarkerResolver{r}
|
||||
}
|
||||
func (r *Resolver) Studio() models.StudioResolver {
|
||||
return &studioResolver{r}
|
||||
}
|
||||
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 }
|
||||
type studioResolver struct{ *Resolver }
|
||||
type tagResolver struct{ *Resolver }
|
||||
|
||||
func (r *queryResolver) MarkerWall(ctx context.Context, q *string) ([]models.SceneMarker, error) {
|
||||
qb := models.NewSceneMarkerQueryBuilder()
|
||||
return qb.Wall(q)
|
||||
}
|
||||
|
||||
func (r *queryResolver) SceneWall(ctx context.Context, q *string) ([]models.Scene, error) {
|
||||
qb := models.NewSceneQueryBuilder()
|
||||
return qb.Wall(q)
|
||||
}
|
||||
|
||||
func (r *queryResolver) MarkerStrings(ctx context.Context, q *string, sort *string) ([]*models.MarkerStringsResultType, error) {
|
||||
qb := models.NewSceneMarkerQueryBuilder()
|
||||
return qb.GetMarkerStrings(q, sort)
|
||||
}
|
||||
|
||||
func (r *queryResolver) ValidGalleriesForScene(ctx context.Context, scene_id *string) ([]models.Gallery, error) {
|
||||
if scene_id == nil {
|
||||
panic("nil scene id") // TODO make scene_id mandatory
|
||||
}
|
||||
sceneID, _ := strconv.Atoi(*scene_id)
|
||||
sqb := models.NewSceneQueryBuilder()
|
||||
scene, err := sqb.Find(sceneID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
qb := models.NewGalleryQueryBuilder()
|
||||
validGalleries, err := qb.ValidGalleriesForScenePath(scene.Path)
|
||||
sceneGallery, _ := qb.FindBySceneID(sceneID, nil)
|
||||
if sceneGallery != nil {
|
||||
validGalleries = append(validGalleries, *sceneGallery)
|
||||
}
|
||||
return validGalleries, nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) Stats(ctx context.Context) (models.StatsResultType, error) {
|
||||
//scenesCount, _ := runCountQuery(buildCountQuery(selectAll("scenes")), nil)
|
||||
//galleryCount, _ := runCountQuery(buildCountQuery(selectAll("galleries")), nil)
|
||||
//performersCount, _ := runCountQuery(buildCountQuery(selectAll("performers")), nil)
|
||||
//studiosCount, _ := runCountQuery(buildCountQuery(selectAll("studios")), nil)
|
||||
//tagsCount, _ := runCountQuery(buildCountQuery(selectAll("tags")), nil)
|
||||
//return StatsResultType{
|
||||
// SceneCount: scenesCount,
|
||||
// GalleryCount: galleryCount,
|
||||
// PerformerCount: performersCount,
|
||||
// StudioCount: studiosCount,
|
||||
// TagCount: tagsCount,
|
||||
//}, nil
|
||||
return models.StatsResultType{}, nil // TODO
|
||||
}
|
||||
|
||||
// Get scene marker tags which show up under the video.
|
||||
func (r *queryResolver) SceneMarkerTags(ctx context.Context, scene_id string) ([]models.SceneMarkerTag, error) {
|
||||
sceneID, _ := strconv.Atoi(scene_id)
|
||||
sqb := models.NewSceneMarkerQueryBuilder()
|
||||
sceneMarkers, err := sqb.FindBySceneID(sceneID, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tags := make(map[int]*models.SceneMarkerTag)
|
||||
var keys []int
|
||||
tqb := models.NewTagQueryBuilder()
|
||||
for _, sceneMarker := range sceneMarkers {
|
||||
if !sceneMarker.PrimaryTagID.Valid {
|
||||
panic("missing primary tag id")
|
||||
}
|
||||
markerPrimaryTag, err := tqb.Find(int(sceneMarker.PrimaryTagID.Int64), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, hasKey := tags[markerPrimaryTag.ID]
|
||||
var sceneMarkerTag *models.SceneMarkerTag
|
||||
if !hasKey {
|
||||
sceneMarkerTag = &models.SceneMarkerTag{ Tag: *markerPrimaryTag }
|
||||
tags[markerPrimaryTag.ID] = sceneMarkerTag
|
||||
keys = append(keys, markerPrimaryTag.ID)
|
||||
} else {
|
||||
sceneMarkerTag = tags[markerPrimaryTag.ID]
|
||||
}
|
||||
tags[markerPrimaryTag.ID].SceneMarkers = append(tags[markerPrimaryTag.ID].SceneMarkers, sceneMarker)
|
||||
}
|
||||
|
||||
// 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
|
||||
})
|
||||
|
||||
var result []models.SceneMarkerTag
|
||||
for _, key := range keys {
|
||||
result = append(result, *tags[key])
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) ScrapeFreeones(ctx context.Context, performer_name string) (*models.ScrapedPerformer, error) {
|
||||
return scraper.GetPerformer(performer_name)
|
||||
}
|
||||
|
||||
func (r *queryResolver) ScrapeFreeonesPerformerList(ctx context.Context, query string) ([]string, error) {
|
||||
return scraper.GetPerformerNames(query)
|
||||
}
|
||||
20
api/resolver_model_gallery.go
Normal file
20
api/resolver_model_gallery.go
Normal file
@@ -0,0 +1,20 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/stashapp/stash/models"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func (r *galleryResolver) ID(ctx context.Context, obj *models.Gallery) (string, error) {
|
||||
return strconv.Itoa(obj.ID), nil
|
||||
}
|
||||
|
||||
func (r *galleryResolver) Title(ctx context.Context, obj *models.Gallery) (*string, error) {
|
||||
return nil, nil // TODO remove this from schema
|
||||
}
|
||||
|
||||
func (r *galleryResolver) Files(ctx context.Context, obj *models.Gallery) ([]models.GalleryFilesType, error) {
|
||||
baseURL, _ := ctx.Value(BaseURLCtxKey).(string)
|
||||
return obj.GetFiles(baseURL), nil
|
||||
}
|
||||
141
api/resolver_model_performer.go
Normal file
141
api/resolver_model_performer.go
Normal file
@@ -0,0 +1,141 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/stashapp/stash/api/urlbuilders"
|
||||
"github.com/stashapp/stash/models"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func (r *performerResolver) ID(ctx context.Context, obj *models.Performer) (string, error) {
|
||||
return strconv.Itoa(obj.ID), nil
|
||||
}
|
||||
|
||||
func (r *performerResolver) Name(ctx context.Context, obj *models.Performer) (*string, error) {
|
||||
if obj.Name.Valid {
|
||||
return &obj.Name.String, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *performerResolver) URL(ctx context.Context, obj *models.Performer) (*string, error) {
|
||||
if obj.Url.Valid {
|
||||
return &obj.Url.String, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *performerResolver) Twitter(ctx context.Context, obj *models.Performer) (*string, error) {
|
||||
if obj.Twitter.Valid {
|
||||
return &obj.Twitter.String, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *performerResolver) Instagram(ctx context.Context, obj *models.Performer) (*string, error) {
|
||||
if obj.Instagram.Valid {
|
||||
return &obj.Instagram.String, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *performerResolver) Birthdate(ctx context.Context, obj *models.Performer) (*string, error) {
|
||||
if obj.Birthdate.Valid {
|
||||
return &obj.Birthdate.String, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *performerResolver) Ethnicity(ctx context.Context, obj *models.Performer) (*string, error) {
|
||||
if obj.Ethnicity.Valid {
|
||||
return &obj.Ethnicity.String, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *performerResolver) Country(ctx context.Context, obj *models.Performer) (*string, error) {
|
||||
if obj.Country.Valid {
|
||||
return &obj.Country.String, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *performerResolver) EyeColor(ctx context.Context, obj *models.Performer) (*string, error) {
|
||||
if obj.EyeColor.Valid {
|
||||
return &obj.EyeColor.String, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *performerResolver) Height(ctx context.Context, obj *models.Performer) (*string, error) {
|
||||
if obj.Height.Valid {
|
||||
return &obj.Height.String, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *performerResolver) Measurements(ctx context.Context, obj *models.Performer) (*string, error) {
|
||||
if obj.Measurements.Valid {
|
||||
return &obj.Measurements.String, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *performerResolver) FakeTits(ctx context.Context, obj *models.Performer) (*string, error) {
|
||||
if obj.FakeTits.Valid {
|
||||
return &obj.FakeTits.String, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *performerResolver) CareerLength(ctx context.Context, obj *models.Performer) (*string, error) {
|
||||
if obj.CareerLength.Valid {
|
||||
return &obj.CareerLength.String, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *performerResolver) Tattoos(ctx context.Context, obj *models.Performer) (*string, error) {
|
||||
if obj.Tattoos.Valid {
|
||||
return &obj.Tattoos.String, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *performerResolver) Piercings(ctx context.Context, obj *models.Performer) (*string, error) {
|
||||
if obj.Piercings.Valid {
|
||||
return &obj.Piercings.String, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *performerResolver) Aliases(ctx context.Context, obj *models.Performer) (*string, error) {
|
||||
if obj.Aliases.Valid {
|
||||
return &obj.Aliases.String, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *performerResolver) Favorite(ctx context.Context, obj *models.Performer) (bool, error) {
|
||||
if obj.Favorite.Valid {
|
||||
return obj.Favorite.Bool, nil
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (r *performerResolver) ImagePath(ctx context.Context, obj *models.Performer) (*string, error) {
|
||||
baseURL, _ := ctx.Value(BaseURLCtxKey).(string)
|
||||
imagePath := urlbuilders.NewPerformerURLBuilder(baseURL, obj.ID).GetPerformerImageUrl()
|
||||
return &imagePath, nil
|
||||
}
|
||||
|
||||
func (r *performerResolver) SceneCount(ctx context.Context, obj *models.Performer) (*int, error) {
|
||||
qb := models.NewSceneQueryBuilder()
|
||||
res, err := qb.CountByPerformerID(obj.ID)
|
||||
return &res, err
|
||||
}
|
||||
|
||||
func (r *performerResolver) Scenes(ctx context.Context, obj *models.Performer) ([]models.Scene, error) {
|
||||
qb := models.NewSceneQueryBuilder()
|
||||
return qb.FindByPerformerID(obj.ID)
|
||||
}
|
||||
116
api/resolver_model_scene.go
Normal file
116
api/resolver_model_scene.go
Normal file
@@ -0,0 +1,116 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/stashapp/stash/api/urlbuilders"
|
||||
"github.com/stashapp/stash/manager"
|
||||
"github.com/stashapp/stash/models"
|
||||
"github.com/stashapp/stash/utils"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func (r *sceneResolver) ID(ctx context.Context, obj *models.Scene) (string, error) {
|
||||
return strconv.Itoa(obj.ID), nil
|
||||
}
|
||||
|
||||
func (r *sceneResolver) Title(ctx context.Context, obj *models.Scene) (*string, error) {
|
||||
if obj.Title.Valid {
|
||||
return &obj.Title.String, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *sceneResolver) Details(ctx context.Context, obj *models.Scene) (*string, error) {
|
||||
if obj.Details.Valid {
|
||||
return &obj.Details.String, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *sceneResolver) URL(ctx context.Context, obj *models.Scene) (*string, error) {
|
||||
if obj.Url.Valid {
|
||||
return &obj.Url.String, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *sceneResolver) Date(ctx context.Context, obj *models.Scene) (*string, error) {
|
||||
if obj.Date.Valid {
|
||||
result := utils.GetYMDFromDatabaseDate(obj.Date.String)
|
||||
return &result, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *sceneResolver) Rating(ctx context.Context, obj *models.Scene) (*int, error) {
|
||||
if obj.Rating.Valid {
|
||||
rating := int(obj.Rating.Int64)
|
||||
return &rating, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *sceneResolver) File(ctx context.Context, obj *models.Scene) (models.SceneFileType, error) {
|
||||
width := int(obj.Width.Int64)
|
||||
height := int(obj.Height.Int64)
|
||||
bitrate := int(obj.Bitrate.Int64)
|
||||
return models.SceneFileType{
|
||||
Size: &obj.Size.String,
|
||||
Duration: &obj.Duration.Float64,
|
||||
VideoCodec: &obj.VideoCodec.String,
|
||||
AudioCodec: &obj.AudioCodec.String,
|
||||
Width: &width,
|
||||
Height: &height,
|
||||
Framerate: &obj.Framerate.Float64,
|
||||
Bitrate: &bitrate,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *sceneResolver) Paths(ctx context.Context, obj *models.Scene) (models.ScenePathsType, error) {
|
||||
baseURL, _ := ctx.Value(BaseURLCtxKey).(string)
|
||||
builder := urlbuilders.NewSceneURLBuilder(baseURL, obj.ID)
|
||||
screenshotPath := builder.GetScreenshotUrl()
|
||||
previewPath := builder.GetStreamPreviewUrl()
|
||||
streamPath := builder.GetStreamUrl()
|
||||
webpPath := builder.GetStreamPreviewImageUrl()
|
||||
vttPath := builder.GetSpriteVttUrl()
|
||||
chaptersVttPath := builder.GetChaptersVttUrl()
|
||||
return models.ScenePathsType{
|
||||
Screenshot: &screenshotPath,
|
||||
Preview: &previewPath,
|
||||
Stream: &streamPath,
|
||||
Webp: &webpPath,
|
||||
Vtt: &vttPath,
|
||||
ChaptersVtt: &chaptersVttPath,
|
||||
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *sceneResolver) IsStreamable(ctx context.Context, obj *models.Scene) (bool, error) {
|
||||
return manager.IsStreamable(obj.Path, obj.Checksum)
|
||||
}
|
||||
|
||||
func (r *sceneResolver) SceneMarkers(ctx context.Context, obj *models.Scene) ([]models.SceneMarker, error) {
|
||||
qb := models.NewSceneMarkerQueryBuilder()
|
||||
return qb.FindBySceneID(obj.ID, nil)
|
||||
}
|
||||
|
||||
func (r *sceneResolver) Gallery(ctx context.Context, obj *models.Scene) (*models.Gallery, error) {
|
||||
qb := models.NewGalleryQueryBuilder()
|
||||
return qb.FindBySceneID(obj.ID, nil)
|
||||
}
|
||||
|
||||
func (r *sceneResolver) Studio(ctx context.Context, obj *models.Scene) (*models.Studio, error) {
|
||||
qb := models.NewStudioQueryBuilder()
|
||||
return qb.FindBySceneID(obj.ID)
|
||||
}
|
||||
|
||||
func (r *sceneResolver) Tags(ctx context.Context, obj *models.Scene) ([]models.Tag, error) {
|
||||
qb := models.NewTagQueryBuilder()
|
||||
return qb.FindBySceneID(obj.ID, nil)
|
||||
}
|
||||
|
||||
func (r *sceneResolver) Performers(ctx context.Context, obj *models.Scene) ([]models.Performer, error) {
|
||||
qb := models.NewPerformerQueryBuilder()
|
||||
return qb.FindBySceneID(obj.ID, nil)
|
||||
}
|
||||
48
api/resolver_model_scene_marker.go
Normal file
48
api/resolver_model_scene_marker.go
Normal file
@@ -0,0 +1,48 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/stashapp/stash/api/urlbuilders"
|
||||
"github.com/stashapp/stash/models"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func (r *sceneMarkerResolver) ID(ctx context.Context, obj *models.SceneMarker) (string, error) {
|
||||
return strconv.Itoa(obj.ID), nil
|
||||
}
|
||||
|
||||
func (r *sceneMarkerResolver) Scene(ctx context.Context, obj *models.SceneMarker) (models.Scene, error) {
|
||||
if !obj.SceneID.Valid {
|
||||
panic("Invalid scene id")
|
||||
}
|
||||
qb := models.NewSceneQueryBuilder()
|
||||
sceneID := int(obj.SceneID.Int64)
|
||||
scene, err := qb.Find(sceneID)
|
||||
return *scene, err
|
||||
}
|
||||
|
||||
func (r *sceneMarkerResolver) PrimaryTag(ctx context.Context, obj *models.SceneMarker) (models.Tag, error) {
|
||||
qb := models.NewTagQueryBuilder()
|
||||
if !obj.PrimaryTagID.Valid {
|
||||
panic("TODO no primary tag id")
|
||||
}
|
||||
tag, err := qb.Find(int(obj.PrimaryTagID.Int64), nil) // TODO make primary tag id not null in DB
|
||||
return *tag, err
|
||||
}
|
||||
|
||||
func (r *sceneMarkerResolver) Tags(ctx context.Context, obj *models.SceneMarker) ([]models.Tag, error) {
|
||||
qb := models.NewTagQueryBuilder()
|
||||
return qb.FindBySceneMarkerID(obj.ID, nil)
|
||||
}
|
||||
|
||||
func (r *sceneMarkerResolver) Stream(ctx context.Context, obj *models.SceneMarker) (string, error) {
|
||||
baseURL, _ := ctx.Value(BaseURLCtxKey).(string)
|
||||
sceneID := int(obj.SceneID.Int64)
|
||||
return urlbuilders.NewSceneURLBuilder(baseURL, sceneID).GetSceneMarkerStreamUrl(obj.ID), nil
|
||||
}
|
||||
|
||||
func (r *sceneMarkerResolver) Preview(ctx context.Context, obj *models.SceneMarker) (string, error) {
|
||||
baseURL, _ := ctx.Value(BaseURLCtxKey).(string)
|
||||
sceneID := int(obj.SceneID.Int64)
|
||||
return urlbuilders.NewSceneURLBuilder(baseURL, sceneID).GetSceneMarkerStreamPreviewUrl(obj.ID), nil
|
||||
}
|
||||
38
api/resolver_model_studio.go
Normal file
38
api/resolver_model_studio.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/stashapp/stash/api/urlbuilders"
|
||||
"github.com/stashapp/stash/models"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func (r *studioResolver) ID(ctx context.Context, obj *models.Studio) (string, error) {
|
||||
return strconv.Itoa(obj.ID), nil
|
||||
}
|
||||
|
||||
func (r *studioResolver) Name(ctx context.Context, obj *models.Studio) (string, error) {
|
||||
if obj.Name.Valid {
|
||||
return obj.Name.String, nil
|
||||
}
|
||||
panic("null name") // TODO make name required
|
||||
}
|
||||
|
||||
func (r *studioResolver) URL(ctx context.Context, obj *models.Studio) (*string, error) {
|
||||
if obj.Url.Valid {
|
||||
return &obj.Url.String, nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (r *studioResolver) ImagePath(ctx context.Context, obj *models.Studio) (*string, error) {
|
||||
baseURL, _ := ctx.Value(BaseURLCtxKey).(string)
|
||||
imagePath := urlbuilders.NewStudioURLBuilder(baseURL, obj.ID).GetStudioImageUrl()
|
||||
return &imagePath, nil
|
||||
}
|
||||
|
||||
func (r *studioResolver) SceneCount(ctx context.Context, obj *models.Studio) (*int, error) {
|
||||
qb := models.NewSceneQueryBuilder()
|
||||
res, err := qb.CountByStudioID(obj.ID)
|
||||
return &res, err
|
||||
}
|
||||
29
api/resolver_model_tag.go
Normal file
29
api/resolver_model_tag.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/stashapp/stash/models"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func (r *tagResolver) ID(ctx context.Context, obj *models.Tag) (string, error) {
|
||||
return strconv.Itoa(obj.ID), nil
|
||||
}
|
||||
|
||||
func (r *tagResolver) SceneCount(ctx context.Context, obj *models.Tag) (*int, error) {
|
||||
qb := models.NewSceneQueryBuilder()
|
||||
if obj == nil {
|
||||
return nil, nil
|
||||
}
|
||||
count, err := qb.CountByTagID(obj.ID)
|
||||
return &count, err
|
||||
}
|
||||
|
||||
func (r *tagResolver) SceneMarkerCount(ctx context.Context, obj *models.Tag) (*int, error) {
|
||||
qb := models.NewSceneMarkerQueryBuilder()
|
||||
if obj == nil {
|
||||
return nil, nil
|
||||
}
|
||||
count, err := qb.CountByTagID(obj.ID)
|
||||
return &count, err
|
||||
}
|
||||
173
api/resolver_mutation_performer.go
Normal file
173
api/resolver_mutation_performer.go
Normal file
@@ -0,0 +1,173 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"github.com/stashapp/stash/database"
|
||||
"github.com/stashapp/stash/models"
|
||||
"github.com/stashapp/stash/utils"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (r *mutationResolver) PerformerCreate(ctx context.Context, input models.PerformerCreateInput) (*models.Performer, error) {
|
||||
// Process the base 64 encoded image string
|
||||
checksum, imageData, err := utils.ProcessBase64Image(input.Image)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Populate a new performer from the input
|
||||
currentTime := time.Now()
|
||||
newPerformer := models.Performer{
|
||||
Image: imageData,
|
||||
Checksum: checksum,
|
||||
CreatedAt: models.SQLiteTimestamp{ Timestamp: currentTime },
|
||||
UpdatedAt: models.SQLiteTimestamp{ Timestamp: currentTime },
|
||||
}
|
||||
if input.Name != nil {
|
||||
newPerformer.Name = sql.NullString{ String: *input.Name, Valid: true }
|
||||
}
|
||||
if input.URL != nil {
|
||||
newPerformer.Url = sql.NullString{ String: *input.URL, Valid: true }
|
||||
}
|
||||
if input.Birthdate != nil {
|
||||
newPerformer.Birthdate = sql.NullString{ String: *input.Birthdate, Valid: true }
|
||||
}
|
||||
if input.Ethnicity != nil {
|
||||
newPerformer.Ethnicity = sql.NullString{ String: *input.Ethnicity, Valid: true }
|
||||
}
|
||||
if input.Country != nil {
|
||||
newPerformer.Country = sql.NullString{ String: *input.Country, Valid: true }
|
||||
}
|
||||
if input.EyeColor != nil {
|
||||
newPerformer.EyeColor = sql.NullString{ String: *input.EyeColor, Valid: true }
|
||||
}
|
||||
if input.Height != nil {
|
||||
newPerformer.Height = sql.NullString{ String: *input.Height, Valid: true }
|
||||
}
|
||||
if input.Measurements != nil {
|
||||
newPerformer.Measurements = sql.NullString{ String: *input.Measurements, Valid: true }
|
||||
}
|
||||
if input.FakeTits != nil {
|
||||
newPerformer.FakeTits = sql.NullString{ String: *input.FakeTits, Valid: true }
|
||||
}
|
||||
if input.CareerLength != nil {
|
||||
newPerformer.CareerLength = sql.NullString{ String: *input.CareerLength, Valid: true }
|
||||
}
|
||||
if input.Tattoos != nil {
|
||||
newPerformer.Tattoos = sql.NullString{ String: *input.Tattoos, Valid: true }
|
||||
}
|
||||
if input.Piercings != nil {
|
||||
newPerformer.Piercings = sql.NullString{ String: *input.Piercings, Valid: true }
|
||||
}
|
||||
if input.Aliases != nil {
|
||||
newPerformer.Aliases = sql.NullString{ String: *input.Aliases, Valid: true }
|
||||
}
|
||||
if input.Twitter != nil {
|
||||
newPerformer.Twitter = sql.NullString{ String: *input.Twitter, Valid: true }
|
||||
}
|
||||
if input.Instagram != nil {
|
||||
newPerformer.Instagram = sql.NullString{ String: *input.Instagram, Valid: true }
|
||||
}
|
||||
if input.Favorite != nil {
|
||||
newPerformer.Favorite = sql.NullBool{ Bool: *input.Favorite, Valid: true }
|
||||
}
|
||||
|
||||
// Start the transaction and save the performer
|
||||
tx := database.DB.MustBeginTx(ctx, nil)
|
||||
qb := models.NewPerformerQueryBuilder()
|
||||
performer, err := qb.Create(newPerformer, tx)
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Commit
|
||||
if err := tx.Commit(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return performer, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) PerformerUpdate(ctx context.Context, input models.PerformerUpdateInput) (*models.Performer, error) {
|
||||
// Populate performer from the input
|
||||
performerID, _ := strconv.Atoi(input.ID)
|
||||
updatedPerformer := models.Performer{
|
||||
ID: performerID,
|
||||
UpdatedAt: models.SQLiteTimestamp{ Timestamp: time.Now() },
|
||||
}
|
||||
if input.Image != nil {
|
||||
checksum, imageData, err := utils.ProcessBase64Image(*input.Image)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
updatedPerformer.Image = imageData
|
||||
updatedPerformer.Checksum = checksum
|
||||
}
|
||||
if input.Name != nil {
|
||||
updatedPerformer.Name = sql.NullString{ String: *input.Name, Valid: true }
|
||||
}
|
||||
if input.URL != nil {
|
||||
updatedPerformer.Url = sql.NullString{ String: *input.URL, Valid: true }
|
||||
}
|
||||
if input.Birthdate != nil {
|
||||
updatedPerformer.Birthdate = sql.NullString{ String: *input.Birthdate, Valid: true }
|
||||
}
|
||||
if input.Ethnicity != nil {
|
||||
updatedPerformer.Ethnicity = sql.NullString{ String: *input.Ethnicity, Valid: true }
|
||||
}
|
||||
if input.Country != nil {
|
||||
updatedPerformer.Country = sql.NullString{ String: *input.Country, Valid: true }
|
||||
}
|
||||
if input.EyeColor != nil {
|
||||
updatedPerformer.EyeColor = sql.NullString{ String: *input.EyeColor, Valid: true }
|
||||
}
|
||||
if input.Height != nil {
|
||||
updatedPerformer.Height = sql.NullString{ String: *input.Height, Valid: true }
|
||||
}
|
||||
if input.Measurements != nil {
|
||||
updatedPerformer.Measurements = sql.NullString{ String: *input.Measurements, Valid: true }
|
||||
}
|
||||
if input.FakeTits != nil {
|
||||
updatedPerformer.FakeTits = sql.NullString{ String: *input.FakeTits, Valid: true }
|
||||
}
|
||||
if input.CareerLength != nil {
|
||||
updatedPerformer.CareerLength = sql.NullString{ String: *input.CareerLength, Valid: true }
|
||||
}
|
||||
if input.Tattoos != nil {
|
||||
updatedPerformer.Tattoos = sql.NullString{ String: *input.Tattoos, Valid: true }
|
||||
}
|
||||
if input.Piercings != nil {
|
||||
updatedPerformer.Piercings = sql.NullString{ String: *input.Piercings, Valid: true }
|
||||
}
|
||||
if input.Aliases != nil {
|
||||
updatedPerformer.Aliases = sql.NullString{ String: *input.Aliases, Valid: true }
|
||||
}
|
||||
if input.Twitter != nil {
|
||||
updatedPerformer.Twitter = sql.NullString{ String: *input.Twitter, Valid: true }
|
||||
}
|
||||
if input.Instagram != nil {
|
||||
updatedPerformer.Instagram = sql.NullString{ String: *input.Instagram, Valid: true }
|
||||
}
|
||||
if input.Favorite != nil {
|
||||
updatedPerformer.Favorite = sql.NullBool{ Bool: *input.Favorite, Valid: true }
|
||||
}
|
||||
|
||||
// Start the transaction and save the performer
|
||||
tx := database.DB.MustBeginTx(ctx, nil)
|
||||
qb := models.NewPerformerQueryBuilder()
|
||||
performer, err := qb.Update(updatedPerformer, tx)
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Commit
|
||||
if err := tx.Commit(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return performer, nil
|
||||
}
|
||||
208
api/resolver_mutation_scene.go
Normal file
208
api/resolver_mutation_scene.go
Normal file
@@ -0,0 +1,208 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"github.com/stashapp/stash/database"
|
||||
"github.com/stashapp/stash/models"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (r *mutationResolver) SceneUpdate(ctx context.Context, input models.SceneUpdateInput) (*models.Scene, error) {
|
||||
// Populate scene from the input
|
||||
sceneID, _ := strconv.Atoi(input.ID)
|
||||
updatedTime := time.Now()
|
||||
updatedScene := models.Scene{
|
||||
ID: sceneID,
|
||||
UpdatedAt: models.SQLiteTimestamp{ Timestamp: updatedTime },
|
||||
}
|
||||
if input.Title != nil {
|
||||
updatedScene.Title = sql.NullString{ String: *input.Title, Valid: true }
|
||||
}
|
||||
if input.Details != nil {
|
||||
updatedScene.Details = sql.NullString{ String: *input.Details, Valid: true }
|
||||
}
|
||||
if input.URL != nil {
|
||||
updatedScene.Url = sql.NullString{ String: *input.URL, Valid: true }
|
||||
}
|
||||
if input.Date != nil {
|
||||
updatedScene.Date = sql.NullString{ String: *input.Date, Valid: true }
|
||||
}
|
||||
if input.Rating != nil {
|
||||
updatedScene.Rating = sql.NullInt64{ Int64: int64(*input.Rating), Valid: true }
|
||||
}
|
||||
if input.StudioID != nil {
|
||||
studioID, _ := strconv.ParseInt(*input.StudioID, 10, 64)
|
||||
updatedScene.StudioID = sql.NullInt64{ Int64: studioID, Valid: true }
|
||||
}
|
||||
|
||||
// Start the transaction and save the scene marker
|
||||
tx := database.DB.MustBeginTx(ctx, nil)
|
||||
qb := models.NewSceneQueryBuilder()
|
||||
jqb := models.NewJoinsQueryBuilder()
|
||||
scene, err := qb.Update(updatedScene, tx)
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if input.GalleryID != nil {
|
||||
// Save the gallery
|
||||
galleryID, _ := strconv.Atoi(*input.GalleryID)
|
||||
updatedGallery := models.Gallery{
|
||||
ID: galleryID,
|
||||
SceneID: sql.NullInt64{ Int64: int64(sceneID), Valid: true },
|
||||
UpdatedAt: models.SQLiteTimestamp{Timestamp: updatedTime},
|
||||
}
|
||||
gqb := models.NewGalleryQueryBuilder()
|
||||
_, err := gqb.Update(updatedGallery, tx)
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// Save the performers
|
||||
var performerJoins []models.PerformersScenes
|
||||
for _, pid := range input.PerformerIds {
|
||||
performerID, _ := strconv.Atoi(pid)
|
||||
performerJoin := models.PerformersScenes{
|
||||
PerformerID: performerID,
|
||||
SceneID: sceneID,
|
||||
}
|
||||
performerJoins = append(performerJoins, performerJoin)
|
||||
}
|
||||
if err := jqb.UpdatePerformersScenes(sceneID, performerJoins, tx); err != nil {
|
||||
_ = tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Save the tags
|
||||
var tagJoins []models.ScenesTags
|
||||
for _, tid := range input.TagIds {
|
||||
tagID, _ := strconv.Atoi(tid)
|
||||
tagJoin := models.ScenesTags{
|
||||
SceneID: sceneID,
|
||||
TagID: tagID,
|
||||
}
|
||||
tagJoins = append(tagJoins, tagJoin)
|
||||
}
|
||||
if err := jqb.UpdateScenesTags(sceneID, tagJoins, tx); err != nil {
|
||||
_ = tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Commit
|
||||
if err := tx.Commit(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return scene, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) SceneMarkerCreate(ctx context.Context, input models.SceneMarkerCreateInput) (*models.SceneMarker, error) {
|
||||
primaryTagID, _ := strconv.Atoi(input.PrimaryTagID)
|
||||
sceneID, _ := strconv.Atoi(input.SceneID)
|
||||
currentTime := time.Now()
|
||||
newSceneMarker := models.SceneMarker{
|
||||
Title: input.Title,
|
||||
Seconds: input.Seconds,
|
||||
PrimaryTagID: sql.NullInt64{ Int64: int64(primaryTagID), Valid: primaryTagID != 0 },
|
||||
SceneID: sql.NullInt64{ Int64: int64(sceneID), Valid: sceneID != 0 },
|
||||
CreatedAt: models.SQLiteTimestamp{ Timestamp: currentTime },
|
||||
UpdatedAt: models.SQLiteTimestamp{ Timestamp: currentTime },
|
||||
}
|
||||
|
||||
// Start the transaction and save the scene marker
|
||||
tx := database.DB.MustBeginTx(ctx, nil)
|
||||
smqb := models.NewSceneMarkerQueryBuilder()
|
||||
jqb := models.NewJoinsQueryBuilder()
|
||||
sceneMarker, err := smqb.Create(newSceneMarker, tx)
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Save the marker tags
|
||||
var markerTagJoins []models.SceneMarkersTags
|
||||
for _, tid := range input.TagIds {
|
||||
tagID, _ := strconv.Atoi(tid)
|
||||
markerTag := models.SceneMarkersTags{
|
||||
SceneMarkerID: sceneMarker.ID,
|
||||
TagID: tagID,
|
||||
}
|
||||
markerTagJoins = append(markerTagJoins, markerTag)
|
||||
}
|
||||
if err := jqb.CreateSceneMarkersTags(markerTagJoins, tx); err != nil {
|
||||
_ = tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Commit
|
||||
if err := tx.Commit(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return sceneMarker, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) SceneMarkerUpdate(ctx context.Context, input models.SceneMarkerUpdateInput) (*models.SceneMarker, error) {
|
||||
// Populate scene marker from the input
|
||||
sceneMarkerID, _ := strconv.Atoi(input.ID)
|
||||
sceneID, _ := strconv.Atoi(input.SceneID)
|
||||
primaryTagID, _ := strconv.Atoi(input.PrimaryTagID)
|
||||
updatedSceneMarker := models.SceneMarker{
|
||||
ID: sceneMarkerID,
|
||||
Title: input.Title,
|
||||
Seconds: input.Seconds,
|
||||
SceneID: sql.NullInt64{ Int64: int64(sceneID), Valid: sceneID != 0 },
|
||||
PrimaryTagID: sql.NullInt64{ Int64: int64(primaryTagID), Valid: primaryTagID != 0 },
|
||||
UpdatedAt: models.SQLiteTimestamp{ Timestamp: time.Now() },
|
||||
}
|
||||
|
||||
// Start the transaction and save the scene marker
|
||||
tx := database.DB.MustBeginTx(ctx, nil)
|
||||
qb := models.NewSceneMarkerQueryBuilder()
|
||||
jqb := models.NewJoinsQueryBuilder()
|
||||
sceneMarker, err := qb.Update(updatedSceneMarker, tx)
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Save the marker tags
|
||||
var markerTagJoins []models.SceneMarkersTags
|
||||
for _, tid := range input.TagIds {
|
||||
tagID, _ := strconv.Atoi(tid)
|
||||
markerTag := models.SceneMarkersTags{
|
||||
SceneMarkerID: sceneMarkerID,
|
||||
TagID: tagID,
|
||||
}
|
||||
markerTagJoins = append(markerTagJoins, markerTag)
|
||||
}
|
||||
if err := jqb.UpdateSceneMarkersTags(sceneMarkerID, markerTagJoins, tx); err != nil {
|
||||
_ = tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Commit
|
||||
if err := tx.Commit(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return sceneMarker, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) SceneMarkerDestroy(ctx context.Context, id string) (bool, error) {
|
||||
qb := models.NewSceneMarkerQueryBuilder()
|
||||
tx := database.DB.MustBeginTx(ctx, nil)
|
||||
if err := qb.Destroy(id, tx); err != nil {
|
||||
_ = tx.Rollback()
|
||||
return false, err
|
||||
}
|
||||
if err := tx.Commit(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
87
api/resolver_mutation_studio.go
Normal file
87
api/resolver_mutation_studio.go
Normal file
@@ -0,0 +1,87 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"github.com/stashapp/stash/database"
|
||||
"github.com/stashapp/stash/models"
|
||||
"github.com/stashapp/stash/utils"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (r *mutationResolver) StudioCreate(ctx context.Context, input models.StudioCreateInput) (*models.Studio, error) {
|
||||
// Process the base 64 encoded image string
|
||||
checksum, imageData, err := utils.ProcessBase64Image(input.Image)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Populate a new studio from the input
|
||||
currentTime := time.Now()
|
||||
newStudio := models.Studio{
|
||||
Image: imageData,
|
||||
Checksum: checksum,
|
||||
Name: sql.NullString{ String: input.Name, Valid: true },
|
||||
CreatedAt: models.SQLiteTimestamp{ Timestamp: currentTime },
|
||||
UpdatedAt: models.SQLiteTimestamp{ Timestamp: currentTime },
|
||||
}
|
||||
if input.URL != nil {
|
||||
newStudio.Url = sql.NullString{ String: *input.URL, Valid: true }
|
||||
}
|
||||
|
||||
// Start the transaction and save the studio
|
||||
tx := database.DB.MustBeginTx(ctx, nil)
|
||||
qb := models.NewStudioQueryBuilder()
|
||||
studio, err := qb.Create(newStudio, tx)
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Commit
|
||||
if err := tx.Commit(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return studio, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) StudioUpdate(ctx context.Context, input models.StudioUpdateInput) (*models.Studio, error) {
|
||||
// Populate studio from the input
|
||||
studioID, _ := strconv.Atoi(input.ID)
|
||||
updatedStudio := models.Studio{
|
||||
ID: studioID,
|
||||
UpdatedAt: models.SQLiteTimestamp{ Timestamp: time.Now() },
|
||||
}
|
||||
if input.Image != nil {
|
||||
checksum, imageData, err := utils.ProcessBase64Image(*input.Image)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
updatedStudio.Image = imageData
|
||||
updatedStudio.Checksum = checksum
|
||||
}
|
||||
if input.Name != nil {
|
||||
updatedStudio.Name = sql.NullString{ String: *input.Name, Valid: true }
|
||||
}
|
||||
if input.URL != nil {
|
||||
updatedStudio.Url = sql.NullString{ String: *input.URL, Valid: true }
|
||||
}
|
||||
|
||||
// Start the transaction and save the studio
|
||||
tx := database.DB.MustBeginTx(ctx, nil)
|
||||
qb := models.NewStudioQueryBuilder()
|
||||
studio, err := qb.Update(updatedStudio, tx)
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Commit
|
||||
if err := tx.Commit(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return studio, nil
|
||||
}
|
||||
74
api/resolver_mutation_tag.go
Normal file
74
api/resolver_mutation_tag.go
Normal file
@@ -0,0 +1,74 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/stashapp/stash/database"
|
||||
"github.com/stashapp/stash/models"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (r *mutationResolver) TagCreate(ctx context.Context, input models.TagCreateInput) (*models.Tag, error) {
|
||||
// Populate a new tag from the input
|
||||
currentTime := time.Now()
|
||||
newTag := models.Tag{
|
||||
Name: input.Name,
|
||||
CreatedAt: models.SQLiteTimestamp{ Timestamp: currentTime },
|
||||
UpdatedAt: models.SQLiteTimestamp{ Timestamp: currentTime },
|
||||
}
|
||||
|
||||
// Start the transaction and save the studio
|
||||
tx := database.DB.MustBeginTx(ctx, nil)
|
||||
qb := models.NewTagQueryBuilder()
|
||||
tag, err := qb.Create(newTag, tx)
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Commit
|
||||
if err := tx.Commit(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tag, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) TagUpdate(ctx context.Context, input models.TagUpdateInput) (*models.Tag, error) {
|
||||
// Populate tag from the input
|
||||
tagID, _ := strconv.Atoi(input.ID)
|
||||
updatedTag := models.Tag{
|
||||
ID: tagID,
|
||||
Name: input.Name,
|
||||
UpdatedAt: models.SQLiteTimestamp{ Timestamp: time.Now() },
|
||||
}
|
||||
|
||||
// Start the transaction and save the tag
|
||||
tx := database.DB.MustBeginTx(ctx, nil)
|
||||
qb := models.NewTagQueryBuilder()
|
||||
tag, err := qb.Update(updatedTag, tx)
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Commit
|
||||
if err := tx.Commit(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return tag, nil
|
||||
}
|
||||
|
||||
func (r *mutationResolver) TagDestroy(ctx context.Context, input models.TagDestroyInput) (bool, error) {
|
||||
qb := models.NewTagQueryBuilder()
|
||||
tx := database.DB.MustBeginTx(ctx, nil)
|
||||
if err := qb.Destroy(input.ID, tx); err != nil {
|
||||
_ = tx.Rollback()
|
||||
return false, err
|
||||
}
|
||||
if err := tx.Commit(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
22
api/resolver_query_find_gallery.go
Normal file
22
api/resolver_query_find_gallery.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/stashapp/stash/models"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func (r *queryResolver) FindGallery(ctx context.Context, id string) (*models.Gallery, error) {
|
||||
qb := models.NewGalleryQueryBuilder()
|
||||
idInt, _ := strconv.Atoi(id)
|
||||
return qb.Find(idInt)
|
||||
}
|
||||
|
||||
func (r *queryResolver) FindGalleries(ctx context.Context, filter *models.FindFilterType) (models.FindGalleriesResultType, error) {
|
||||
qb := models.NewGalleryQueryBuilder()
|
||||
galleries, total := qb.Query(filter)
|
||||
return models.FindGalleriesResultType{
|
||||
Count: total,
|
||||
Galleries: galleries,
|
||||
}, nil
|
||||
}
|
||||
27
api/resolver_query_find_performer.go
Normal file
27
api/resolver_query_find_performer.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/stashapp/stash/models"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func (r *queryResolver) FindPerformer(ctx context.Context, id string) (*models.Performer, error) {
|
||||
qb := models.NewPerformerQueryBuilder()
|
||||
idInt, _ := strconv.Atoi(id)
|
||||
return qb.Find(idInt)
|
||||
}
|
||||
|
||||
func (r *queryResolver) FindPerformers(ctx context.Context, performer_filter *models.PerformerFilterType, filter *models.FindFilterType) (models.FindPerformersResultType, error) {
|
||||
qb := models.NewPerformerQueryBuilder()
|
||||
performers, total := qb.Query(performer_filter, filter)
|
||||
return models.FindPerformersResultType{
|
||||
Count: total,
|
||||
Performers: performers,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) AllPerformers(ctx context.Context) ([]models.Performer, error) {
|
||||
qb := models.NewPerformerQueryBuilder()
|
||||
return qb.All()
|
||||
}
|
||||
29
api/resolver_query_find_scene.go
Normal file
29
api/resolver_query_find_scene.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/stashapp/stash/models"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func (r *queryResolver) FindScene(ctx context.Context, id *string, checksum *string) (*models.Scene, error) {
|
||||
qb := models.NewSceneQueryBuilder()
|
||||
idInt, _ := strconv.Atoi(*id)
|
||||
var scene *models.Scene
|
||||
var err error
|
||||
if id != nil {
|
||||
scene, err = qb.Find(idInt)
|
||||
} else if checksum != nil {
|
||||
scene, err = qb.FindByChecksum(*checksum)
|
||||
}
|
||||
return scene, err
|
||||
}
|
||||
|
||||
func (r *queryResolver) FindScenes(ctx context.Context, scene_filter *models.SceneFilterType, scene_ids []int, filter *models.FindFilterType) (models.FindScenesResultType, error) {
|
||||
qb := models.NewSceneQueryBuilder()
|
||||
scenes, total := qb.Query(scene_filter, filter)
|
||||
return models.FindScenesResultType{
|
||||
Count: total,
|
||||
Scenes: scenes,
|
||||
}, nil
|
||||
}
|
||||
15
api/resolver_query_find_scene_marker.go
Normal file
15
api/resolver_query_find_scene_marker.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/stashapp/stash/models"
|
||||
)
|
||||
|
||||
func (r *queryResolver) FindSceneMarkers(ctx context.Context, scene_marker_filter *models.SceneMarkerFilterType, filter *models.FindFilterType) (models.FindSceneMarkersResultType, error) {
|
||||
qb := models.NewSceneMarkerQueryBuilder()
|
||||
sceneMarkers, total := qb.Query(scene_marker_filter, filter)
|
||||
return models.FindSceneMarkersResultType{
|
||||
Count: total,
|
||||
SceneMarkers: sceneMarkers,
|
||||
}, nil
|
||||
}
|
||||
27
api/resolver_query_find_studio.go
Normal file
27
api/resolver_query_find_studio.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/stashapp/stash/models"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func (r *queryResolver) FindStudio(ctx context.Context, id string) (*models.Studio, error) {
|
||||
qb := models.NewStudioQueryBuilder()
|
||||
idInt, _ := strconv.Atoi(id)
|
||||
return qb.Find(idInt, nil)
|
||||
}
|
||||
|
||||
func (r *queryResolver) FindStudios(ctx context.Context, filter *models.FindFilterType) (models.FindStudiosResultType, error) {
|
||||
qb := models.NewStudioQueryBuilder()
|
||||
studios, total := qb.Query(filter)
|
||||
return models.FindStudiosResultType{
|
||||
Count: total,
|
||||
Studios: studios,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) AllStudios(ctx context.Context) ([]models.Studio, error) {
|
||||
qb := models.NewStudioQueryBuilder()
|
||||
return qb.All()
|
||||
}
|
||||
18
api/resolver_query_find_tag.go
Normal file
18
api/resolver_query_find_tag.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/stashapp/stash/models"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func (r *queryResolver) FindTag(ctx context.Context, id string) (*models.Tag, error) {
|
||||
qb := models.NewTagQueryBuilder()
|
||||
idInt, _ := strconv.Atoi(id)
|
||||
return qb.Find(idInt, nil)
|
||||
}
|
||||
|
||||
func (r *queryResolver) AllTags(ctx context.Context) ([]models.Tag, error) {
|
||||
qb := models.NewTagQueryBuilder()
|
||||
return qb.All()
|
||||
}
|
||||
29
api/resolver_query_metadata.go
Normal file
29
api/resolver_query_metadata.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/stashapp/stash/manager"
|
||||
)
|
||||
|
||||
func (r *queryResolver) MetadataScan(ctx context.Context) (string, error) {
|
||||
manager.GetInstance().Scan()
|
||||
return "todo", nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) MetadataImport(ctx context.Context) (string, error) {
|
||||
manager.GetInstance().Import()
|
||||
return "todo", nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) MetadataExport(ctx context.Context) (string, error) {
|
||||
manager.GetInstance().Export()
|
||||
return "todo", nil
|
||||
}
|
||||
|
||||
func (r *queryResolver) MetadataGenerate(ctx context.Context) (string, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (r *queryResolver) MetadataClean(ctx context.Context) (string, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
7
api/resolver_subscription_metadata.go
Normal file
7
api/resolver_subscription_metadata.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package api
|
||||
|
||||
import "context"
|
||||
|
||||
func (r *subscriptionResolver) MetadataUpdate(ctx context.Context) (<-chan string, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
54
api/routes_gallery.go
Normal file
54
api/routes_gallery.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/stashapp/stash/models"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type galleryRoutes struct{}
|
||||
|
||||
func (rs galleryRoutes) Routes() chi.Router {
|
||||
r := chi.NewRouter()
|
||||
|
||||
r.Route("/{galleryId}", func(r chi.Router) {
|
||||
r.Use(GalleryCtx)
|
||||
r.Get("/{fileIndex}", rs.File)
|
||||
})
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (rs galleryRoutes) File(w http.ResponseWriter, r *http.Request) {
|
||||
gallery := r.Context().Value("gallery").(*models.Gallery)
|
||||
fileIndex, _ := strconv.Atoi(chi.URLParam(r, "fileIndex"))
|
||||
thumb := r.URL.Query().Get("thumb")
|
||||
w.Header().Add("Cache-Control", "max-age=604800000") // 1 Week
|
||||
if thumb == "true" {
|
||||
_, _ = w.Write(gallery.GetThumbnail(fileIndex))
|
||||
} else {
|
||||
_, _ = w.Write(gallery.GetImage(fileIndex))
|
||||
}
|
||||
}
|
||||
|
||||
func GalleryCtx(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
galleryID, err := strconv.Atoi(chi.URLParam(r, "galleryId"))
|
||||
if err != nil {
|
||||
http.Error(w, http.StatusText(404), 404)
|
||||
return
|
||||
}
|
||||
|
||||
qb := models.NewGalleryQueryBuilder()
|
||||
gallery, err := qb.Find(galleryID)
|
||||
if err != nil {
|
||||
http.Error(w, http.StatusText(404), 404)
|
||||
return
|
||||
}
|
||||
|
||||
ctx := context.WithValue(r.Context(), "gallery", gallery)
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
})
|
||||
}
|
||||
47
api/routes_performer.go
Normal file
47
api/routes_performer.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/stashapp/stash/models"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type performerRoutes struct{}
|
||||
|
||||
func (rs performerRoutes) Routes() chi.Router {
|
||||
r := chi.NewRouter()
|
||||
|
||||
r.Route("/{performerId}", func(r chi.Router) {
|
||||
r.Use(PerformerCtx)
|
||||
r.Get("/image", rs.Image)
|
||||
})
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (rs performerRoutes) Image(w http.ResponseWriter, r *http.Request) {
|
||||
performer := r.Context().Value("performer").(*models.Performer)
|
||||
_, _ = w.Write(performer.Image)
|
||||
}
|
||||
|
||||
func PerformerCtx(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
performerID, err := strconv.Atoi(chi.URLParam(r, "performerId"))
|
||||
if err != nil {
|
||||
http.Error(w, http.StatusText(404), 404)
|
||||
return
|
||||
}
|
||||
|
||||
qb := models.NewPerformerQueryBuilder()
|
||||
performer, err := qb.Find(performerID)
|
||||
if err != nil {
|
||||
http.Error(w, http.StatusText(404), 404)
|
||||
return
|
||||
}
|
||||
|
||||
ctx := context.WithValue(r.Context(), "performer", performer)
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
})
|
||||
}
|
||||
151
api/routes_scene.go
Normal file
151
api/routes_scene.go
Normal file
@@ -0,0 +1,151 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/stashapp/stash/logger"
|
||||
"github.com/stashapp/stash/manager"
|
||||
"github.com/stashapp/stash/models"
|
||||
"github.com/stashapp/stash/utils"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type sceneRoutes struct{}
|
||||
|
||||
func (rs sceneRoutes) Routes() chi.Router {
|
||||
r := chi.NewRouter()
|
||||
|
||||
r.Route("/{sceneId}", func(r chi.Router) {
|
||||
r.Use(SceneCtx)
|
||||
r.Get("/stream", rs.Stream)
|
||||
r.Get("/stream.mp4", rs.Stream)
|
||||
r.Get("/screenshot", rs.Screenshot)
|
||||
r.Get("/preview", rs.Preview)
|
||||
r.Get("/webp", rs.Webp)
|
||||
r.Get("/vtt/chapter", rs.ChapterVtt)
|
||||
|
||||
r.Get("/scene_marker/{sceneMarkerId}/stream", rs.SceneMarkerStream)
|
||||
r.Get("/scene_marker/{sceneMarkerId}/preview", rs.SceneMarkerPreview)
|
||||
})
|
||||
r.With(SceneCtx).Get("/{sceneId}_thumbs.vtt", rs.VttThumbs)
|
||||
r.With(SceneCtx).Get("/{sceneId}_sprite.jpg", rs.VttSprite)
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
// region Handlers
|
||||
|
||||
func (rs sceneRoutes) Stream(w http.ResponseWriter, r *http.Request) {
|
||||
scene := r.Context().Value("scene").(*models.Scene)
|
||||
filepath := manager.GetInstance().Paths.Scene.GetStreamPath(scene.Path, scene.Checksum)
|
||||
http.ServeFile(w, r, filepath)
|
||||
}
|
||||
|
||||
func (rs sceneRoutes) Screenshot(w http.ResponseWriter, r *http.Request) {
|
||||
scene := r.Context().Value("scene").(*models.Scene)
|
||||
filepath := manager.GetInstance().Paths.Scene.GetScreenshotPath(scene.Checksum)
|
||||
http.ServeFile(w, r, filepath)
|
||||
}
|
||||
|
||||
func (rs sceneRoutes) Preview(w http.ResponseWriter, r *http.Request) {
|
||||
scene := r.Context().Value("scene").(*models.Scene)
|
||||
filepath := manager.GetInstance().Paths.Scene.GetStreamPreviewPath(scene.Checksum)
|
||||
http.ServeFile(w, r, filepath)
|
||||
}
|
||||
|
||||
func (rs sceneRoutes) Webp(w http.ResponseWriter, r *http.Request) {
|
||||
scene := r.Context().Value("scene").(*models.Scene)
|
||||
filepath := manager.GetInstance().Paths.Scene.GetStreamPreviewImagePath(scene.Checksum)
|
||||
http.ServeFile(w, r, filepath)
|
||||
}
|
||||
|
||||
func (rs sceneRoutes) ChapterVtt(w http.ResponseWriter, r *http.Request) {
|
||||
scene := r.Context().Value("scene").(*models.Scene)
|
||||
qb := models.NewSceneMarkerQueryBuilder()
|
||||
sceneMarkers, err := qb.FindBySceneID(scene.ID, nil)
|
||||
if err != nil {
|
||||
panic("invalid scene markers for chapter vtt")
|
||||
}
|
||||
|
||||
vttLines := []string{"WEBVTT", ""}
|
||||
for _, marker := range sceneMarkers {
|
||||
time := utils.GetVTTTime(marker.Seconds)
|
||||
vttLines = append(vttLines, time + " --> " + time)
|
||||
vttLines = append(vttLines, marker.Title)
|
||||
vttLines = append(vttLines, "")
|
||||
}
|
||||
vtt := strings.Join(vttLines, "\n")
|
||||
|
||||
w.Header().Set("Content-Type", "text/vtt")
|
||||
_, _ = w.Write([]byte(vtt))
|
||||
}
|
||||
|
||||
func (rs sceneRoutes) VttThumbs(w http.ResponseWriter, r *http.Request) {
|
||||
scene := r.Context().Value("scene").(*models.Scene)
|
||||
w.Header().Set("Content-Type", "text/vtt")
|
||||
filepath := manager.GetInstance().Paths.Scene.GetSpriteVttFilePath(scene.Checksum)
|
||||
http.ServeFile(w, r, filepath)
|
||||
}
|
||||
|
||||
func (rs sceneRoutes) VttSprite(w http.ResponseWriter, r *http.Request) {
|
||||
scene := r.Context().Value("scene").(*models.Scene)
|
||||
w.Header().Set("Content-Type", "image/jpeg")
|
||||
filepath := manager.GetInstance().Paths.Scene.GetSpriteImageFilePath(scene.Checksum)
|
||||
http.ServeFile(w, r, filepath)
|
||||
}
|
||||
|
||||
func (rs sceneRoutes) SceneMarkerStream(w http.ResponseWriter, r *http.Request) {
|
||||
scene := r.Context().Value("scene").(*models.Scene)
|
||||
sceneMarkerID, _ := strconv.Atoi(chi.URLParam(r, "sceneMarkerId"))
|
||||
qb := models.NewSceneMarkerQueryBuilder()
|
||||
sceneMarker, err := qb.Find(sceneMarkerID)
|
||||
if err != nil {
|
||||
logger.Warn("Error when getting scene marker for stream")
|
||||
http.Error(w, http.StatusText(404), 404)
|
||||
return
|
||||
}
|
||||
filepath := manager.GetInstance().Paths.SceneMarkers.GetStreamPath(scene.Checksum, int(sceneMarker.Seconds))
|
||||
http.ServeFile(w, r, filepath)
|
||||
}
|
||||
|
||||
func (rs sceneRoutes) SceneMarkerPreview(w http.ResponseWriter, r *http.Request) {
|
||||
scene := r.Context().Value("scene").(*models.Scene)
|
||||
sceneMarkerID, _ := strconv.Atoi(chi.URLParam(r, "sceneMarkerId"))
|
||||
qb := models.NewSceneMarkerQueryBuilder()
|
||||
sceneMarker, err := qb.Find(sceneMarkerID)
|
||||
if err != nil {
|
||||
logger.Warn("Error when getting scene marker for stream")
|
||||
http.Error(w, http.StatusText(404), 404)
|
||||
return
|
||||
}
|
||||
filepath := manager.GetInstance().Paths.SceneMarkers.GetStreamPreviewImagePath(scene.Checksum, int(sceneMarker.Seconds))
|
||||
http.ServeFile(w, r, filepath)
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
func SceneCtx(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
sceneIdentifierQueryParam := chi.URLParam(r, "sceneId")
|
||||
sceneID, _ := strconv.Atoi(sceneIdentifierQueryParam)
|
||||
|
||||
var scene *models.Scene
|
||||
var err error
|
||||
qb := models.NewSceneQueryBuilder()
|
||||
if sceneID == 0 {
|
||||
scene, err = qb.FindByChecksum(sceneIdentifierQueryParam)
|
||||
} else {
|
||||
scene, err = qb.Find(sceneID)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
http.Error(w, http.StatusText(404), 404)
|
||||
return
|
||||
}
|
||||
|
||||
ctx := context.WithValue(r.Context(), "scene", scene)
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
})
|
||||
}
|
||||
47
api/routes_studio.go
Normal file
47
api/routes_studio.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/stashapp/stash/models"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type studioRoutes struct{}
|
||||
|
||||
func (rs studioRoutes) Routes() chi.Router {
|
||||
r := chi.NewRouter()
|
||||
|
||||
r.Route("/{studioId}", func(r chi.Router) {
|
||||
r.Use(StudioCtx)
|
||||
r.Get("/image", rs.Image)
|
||||
})
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (rs studioRoutes) Image(w http.ResponseWriter, r *http.Request) {
|
||||
studio := r.Context().Value("studio").(*models.Studio)
|
||||
_, _ = w.Write(studio.Image)
|
||||
}
|
||||
|
||||
func StudioCtx(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
studioID, err := strconv.Atoi(chi.URLParam(r, "studioId"))
|
||||
if err != nil {
|
||||
http.Error(w, http.StatusText(404), 404)
|
||||
return
|
||||
}
|
||||
|
||||
qb := models.NewStudioQueryBuilder()
|
||||
studio, err := qb.Find(studioID, nil)
|
||||
if err != nil {
|
||||
http.Error(w, http.StatusText(404), 404)
|
||||
return
|
||||
}
|
||||
|
||||
ctx := context.WithValue(r.Context(), "studio", studio)
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
})
|
||||
}
|
||||
139
api/server.go
Normal file
139
api/server.go
Normal file
@@ -0,0 +1,139 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/99designs/gqlgen/handler"
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/go-chi/chi/middleware"
|
||||
"github.com/gobuffalo/packr/v2"
|
||||
"github.com/rs/cors"
|
||||
"github.com/stashapp/stash/logger"
|
||||
"github.com/stashapp/stash/models"
|
||||
"net/http"
|
||||
"path"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const httpPort = "9998"
|
||||
const httpsPort = "9999"
|
||||
|
||||
var certsBox *packr.Box
|
||||
var uiBox *packr.Box
|
||||
|
||||
func Start() {
|
||||
//port := os.Getenv("PORT")
|
||||
//if port == "" {
|
||||
// port = defaultPort
|
||||
//}
|
||||
|
||||
certsBox = packr.New("Cert Box", "../../certs")
|
||||
uiBox = packr.New("UI Box", "../../ui/v1/dist/stash-frontend")
|
||||
|
||||
r := chi.NewRouter()
|
||||
|
||||
r.Use(middleware.Recoverer)
|
||||
r.Use(middleware.Logger)
|
||||
r.Use(middleware.DefaultCompress)
|
||||
r.Use(middleware.StripSlashes)
|
||||
r.Use(cors.AllowAll().Handler)
|
||||
r.Use(BaseURLMiddleware)
|
||||
|
||||
recoverFunc := handler.RecoverFunc(func(ctx context.Context, err interface{}) error {
|
||||
logger.Error(err)
|
||||
debug.PrintStack()
|
||||
|
||||
message := fmt.Sprintf("Internal system error. Error <%v>", err)
|
||||
return errors.New(message)
|
||||
})
|
||||
requestMiddleware := handler.RequestMiddleware(func(ctx context.Context, next func(ctx context.Context) []byte) []byte {
|
||||
//api.GetRequestContext(ctx).Variables[]
|
||||
return next(ctx)
|
||||
})
|
||||
gqlHandler := handler.GraphQL(models.NewExecutableSchema(models.Config{Resolvers: &Resolver{}}), recoverFunc, requestMiddleware)
|
||||
|
||||
// https://stash.server:9999/certs/server.crt
|
||||
r.Handle("/certs/*", http.FileServer(certsBox))
|
||||
|
||||
r.Handle("/graphql", gqlHandler)
|
||||
r.Handle("/playground", handler.Playground("GraphQL playground", "/graphql"))
|
||||
|
||||
r.Mount("/gallery", galleryRoutes{}.Routes())
|
||||
r.Mount("/performer", performerRoutes{}.Routes())
|
||||
r.Mount("/scene", sceneRoutes{}.Routes())
|
||||
r.Mount("/studio", studioRoutes{}.Routes())
|
||||
|
||||
// Serve the angular app
|
||||
r.HandleFunc("/*", func(w http.ResponseWriter, r *http.Request) {
|
||||
ext := path.Ext(r.URL.Path)
|
||||
if ext == ".html" || ext == "" {
|
||||
data := uiBox.Bytes("index.html")
|
||||
_, _ = w.Write(data)
|
||||
} else {
|
||||
http.FileServer(uiBox).ServeHTTP(w, r)
|
||||
}
|
||||
})
|
||||
|
||||
httpsServer := &http.Server{
|
||||
Addr: ":"+httpsPort,
|
||||
Handler: r,
|
||||
TLSConfig: makeTLSConfig(),
|
||||
}
|
||||
server := &http.Server{
|
||||
Addr: ":"+httpPort,
|
||||
Handler: r,
|
||||
}
|
||||
|
||||
go func() {
|
||||
logger.Infof("stash is running on HTTP at http://localhost:9998/")
|
||||
logger.Fatal(server.ListenAndServe())
|
||||
}()
|
||||
|
||||
logger.Infof("stash is running on HTTPS at https://localhost:9999/")
|
||||
logger.Fatal(httpsServer.ListenAndServeTLS("", ""))
|
||||
}
|
||||
|
||||
func makeTLSConfig() *tls.Config {
|
||||
cert, err := certsBox.Find("server.crt")
|
||||
key, err := certsBox.Find("server.key")
|
||||
|
||||
certs := make([]tls.Certificate, 1)
|
||||
certs[0], err = tls.X509KeyPair(cert, key)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
tlsConfig := &tls.Config{
|
||||
Certificates: certs,
|
||||
}
|
||||
|
||||
return tlsConfig
|
||||
}
|
||||
|
||||
|
||||
type contextKey struct {
|
||||
name string
|
||||
}
|
||||
var (
|
||||
BaseURLCtxKey = &contextKey{"BaseURL"}
|
||||
)
|
||||
func BaseURLMiddleware(next http.Handler) http.Handler {
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
var scheme string
|
||||
if strings.Compare("https", r.URL.Scheme) == 0 || r.Proto == "HTTP/2.0" {
|
||||
scheme = "https"
|
||||
} else {
|
||||
scheme = "http"
|
||||
}
|
||||
baseURL := scheme + "://" + r.Host
|
||||
|
||||
r = r.WithContext(context.WithValue(ctx, BaseURLCtxKey, baseURL))
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
}
|
||||
return http.HandlerFunc(fn)
|
||||
}
|
||||
19
api/urlbuilders/gallery.go
Normal file
19
api/urlbuilders/gallery.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package urlbuilders
|
||||
|
||||
import "strconv"
|
||||
|
||||
type galleryURLBuilder struct {
|
||||
BaseURL string
|
||||
GalleryID string
|
||||
}
|
||||
|
||||
func NewGalleryURLBuilder(baseURL string, galleryID int) galleryURLBuilder {
|
||||
return galleryURLBuilder{
|
||||
BaseURL: baseURL,
|
||||
GalleryID: strconv.Itoa(galleryID),
|
||||
}
|
||||
}
|
||||
|
||||
func (b galleryURLBuilder) GetGalleryImageUrl(fileIndex int) string {
|
||||
return b.BaseURL + "/gallery/" + b.GalleryID + "/" + strconv.Itoa(fileIndex)
|
||||
}
|
||||
19
api/urlbuilders/performer.go
Normal file
19
api/urlbuilders/performer.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package urlbuilders
|
||||
|
||||
import "strconv"
|
||||
|
||||
type performerURLBuilder struct {
|
||||
BaseURL string
|
||||
PerformerID string
|
||||
}
|
||||
|
||||
func NewPerformerURLBuilder(baseURL string, performerID int) performerURLBuilder {
|
||||
return performerURLBuilder{
|
||||
BaseURL: baseURL,
|
||||
PerformerID: strconv.Itoa(performerID),
|
||||
}
|
||||
}
|
||||
|
||||
func (b performerURLBuilder) GetPerformerImageUrl() string {
|
||||
return b.BaseURL + "/performer/" + b.PerformerID + "/image"
|
||||
}
|
||||
47
api/urlbuilders/scene.go
Normal file
47
api/urlbuilders/scene.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package urlbuilders
|
||||
|
||||
import "strconv"
|
||||
|
||||
type sceneURLBuilder struct {
|
||||
BaseURL string
|
||||
SceneID string
|
||||
}
|
||||
|
||||
func NewSceneURLBuilder(baseURL string, sceneID int) sceneURLBuilder {
|
||||
return sceneURLBuilder{
|
||||
BaseURL: baseURL,
|
||||
SceneID: strconv.Itoa(sceneID),
|
||||
}
|
||||
}
|
||||
|
||||
func (b sceneURLBuilder) GetStreamUrl() string {
|
||||
return b.BaseURL + "/scene/" + b.SceneID + "/stream.mp4"
|
||||
}
|
||||
|
||||
func (b sceneURLBuilder) GetStreamPreviewUrl() string {
|
||||
return b.BaseURL + "/scene/" + b.SceneID + "/preview"
|
||||
}
|
||||
|
||||
func (b sceneURLBuilder) GetStreamPreviewImageUrl() string {
|
||||
return b.BaseURL + "/scene/" + b.SceneID + "/webp"
|
||||
}
|
||||
|
||||
func (b sceneURLBuilder) GetSpriteVttUrl() string {
|
||||
return b.BaseURL + "/scene/" + b.SceneID + "_thumbs.vtt"
|
||||
}
|
||||
|
||||
func (b sceneURLBuilder) GetScreenshotUrl() string {
|
||||
return b.BaseURL + "/scene/" + b.SceneID + "/screenshot"
|
||||
}
|
||||
|
||||
func (b sceneURLBuilder) GetChaptersVttUrl() string {
|
||||
return b.BaseURL + "/scene/" + b.SceneID + "/vtt/chapter"
|
||||
}
|
||||
|
||||
func (b sceneURLBuilder) GetSceneMarkerStreamUrl(sceneMarkerId int) string {
|
||||
return b.BaseURL + "/scene/" + b.SceneID + "/scene_marker/" + strconv.Itoa(sceneMarkerId) + "/stream"
|
||||
}
|
||||
|
||||
func (b sceneURLBuilder) GetSceneMarkerStreamPreviewUrl(sceneMarkerId int) string {
|
||||
return b.BaseURL + "/scene/" + b.SceneID + "/scene_marker/" + strconv.Itoa(sceneMarkerId) + "/preview"
|
||||
}
|
||||
19
api/urlbuilders/studio.go
Normal file
19
api/urlbuilders/studio.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package urlbuilders
|
||||
|
||||
import "strconv"
|
||||
|
||||
type studioURLBuilder struct {
|
||||
BaseURL string
|
||||
StudioID string
|
||||
}
|
||||
|
||||
func NewStudioURLBuilder(baseURL string, studioID int) studioURLBuilder {
|
||||
return studioURLBuilder{
|
||||
BaseURL: baseURL,
|
||||
StudioID: strconv.Itoa(studioID),
|
||||
}
|
||||
}
|
||||
|
||||
func (b studioURLBuilder) GetStudioImageUrl() string {
|
||||
return b.BaseURL + "/studio/" + b.StudioID + "/image"
|
||||
}
|
||||
Reference in New Issue
Block a user