1
Fork 0

Expose media_type to graphql

- Make video thumbnail accessible from graphql
This commit is contained in:
viktorstrate 2020-07-11 14:21:10 +02:00
parent 9e5480188b
commit 990a592fcc
9 changed files with 126 additions and 20 deletions

View File

@ -81,6 +81,7 @@ type ComplexityRoot struct {
Shares func(childComplexity int) int Shares func(childComplexity int) int
Thumbnail func(childComplexity int) int Thumbnail func(childComplexity int) int
Title func(childComplexity int) int Title func(childComplexity int) int
Type func(childComplexity int) int
} }
MediaDownload struct { MediaDownload struct {
@ -433,6 +434,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in
return e.complexity.Media.Title(childComplexity), true return e.complexity.Media.Title(childComplexity), true
case "Media.type":
if e.complexity.Media.Type == nil {
break
}
return e.complexity.Media.Type(childComplexity), true
case "MediaDownload.height": case "MediaDownload.height":
if e.complexity.MediaDownload.Height == nil { if e.complexity.MediaDownload.Height == nil {
break break
@ -1304,6 +1312,11 @@ type MediaDownload {
url: String! url: String!
} }
enum MediaType {
photo
video
}
type Media { type Media {
id: Int! id: Int!
title: String! title: String!
@ -1317,6 +1330,7 @@ type Media {
album: Album! album: Album!
exif: MediaEXIF exif: MediaEXIF
favorite: Boolean! favorite: Boolean!
type: MediaType!
shares: [ShareToken!]! shares: [ShareToken!]!
downloads: [MediaDownload!]! downloads: [MediaDownload!]!
@ -2620,6 +2634,40 @@ func (ec *executionContext) _Media_favorite(ctx context.Context, field graphql.C
return ec.marshalNBoolean2bool(ctx, field.Selections, res) return ec.marshalNBoolean2bool(ctx, field.Selections, res)
} }
func (ec *executionContext) _Media_type(ctx context.Context, field graphql.CollectedField, obj *models.Media) (ret graphql.Marshaler) {
defer func() {
if r := recover(); r != nil {
ec.Error(ctx, ec.Recover(ctx, r))
ret = graphql.Null
}
}()
fc := &graphql.FieldContext{
Object: "Media",
Field: field,
Args: nil,
IsMethod: false,
}
ctx = graphql.WithFieldContext(ctx, fc)
resTmp, err := ec.ResolverMiddleware(ctx, func(rctx context.Context) (interface{}, error) {
ctx = rctx // use context from middleware stack in children
return obj.Type, nil
})
if err != nil {
ec.Error(ctx, err)
return graphql.Null
}
if resTmp == nil {
if !graphql.HasFieldError(ctx, fc) {
ec.Errorf(ctx, "must not be null")
}
return graphql.Null
}
res := resTmp.(models.MediaType)
fc.Result = res
return ec.marshalNMediaType2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐMediaType(ctx, field.Selections, res)
}
func (ec *executionContext) _Media_shares(ctx context.Context, field graphql.CollectedField, obj *models.Media) (ret graphql.Marshaler) { func (ec *executionContext) _Media_shares(ctx context.Context, field graphql.CollectedField, obj *models.Media) (ret graphql.Marshaler) {
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
@ -6669,6 +6717,11 @@ func (ec *executionContext) _Media(ctx context.Context, sel ast.SelectionSet, ob
if out.Values[i] == graphql.Null { if out.Values[i] == graphql.Null {
atomic.AddUint32(&invalids, 1) atomic.AddUint32(&invalids, 1)
} }
case "type":
out.Values[i] = ec._Media_type(ctx, field, obj)
if out.Values[i] == graphql.Null {
atomic.AddUint32(&invalids, 1)
}
case "shares": case "shares":
field := field field := field
out.Concurrently(i, func() (res graphql.Marshaler) { out.Concurrently(i, func() (res graphql.Marshaler) {
@ -7815,6 +7868,15 @@ func (ec *executionContext) marshalNMediaDownload2ᚖgithubᚗcomᚋviktorstrate
return ec._MediaDownload(ctx, sel, v) return ec._MediaDownload(ctx, sel, v)
} }
func (ec *executionContext) unmarshalNMediaType2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐMediaType(ctx context.Context, v interface{}) (models.MediaType, error) {
var res models.MediaType
return res, res.UnmarshalGQL(v)
}
func (ec *executionContext) marshalNMediaType2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐMediaType(ctx context.Context, sel ast.SelectionSet, v models.MediaType) graphql.Marshaler {
return v
}
func (ec *executionContext) marshalNMediaURL2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐMediaURL(ctx context.Context, sel ast.SelectionSet, v models.MediaURL) graphql.Marshaler { func (ec *executionContext) marshalNMediaURL2githubᚗcomᚋviktorstrateᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐMediaURL(ctx context.Context, sel ast.SelectionSet, v models.MediaURL) graphql.Marshaler {
return ec._MediaURL(ctx, sel, &v) return ec._MediaURL(ctx, sel, &v)
} }

View File

@ -58,6 +58,47 @@ type SiteInfo struct {
InitialSetup bool `json:"initialSetup"` InitialSetup bool `json:"initialSetup"`
} }
type MediaType string
const (
MediaTypePhoto MediaType = "photo"
MediaTypeVideo MediaType = "video"
)
var AllMediaType = []MediaType{
MediaTypePhoto,
MediaTypeVideo,
}
func (e MediaType) IsValid() bool {
switch e {
case MediaTypePhoto, MediaTypeVideo:
return true
}
return false
}
func (e MediaType) String() string {
return string(e)
}
func (e *MediaType) UnmarshalGQL(v interface{}) error {
str, ok := v.(string)
if !ok {
return fmt.Errorf("enums must be strings")
}
*e = MediaType(str)
if !e.IsValid() {
return fmt.Errorf("%s is not a valid MediaType", str)
}
return nil
}
func (e MediaType) MarshalGQL(w io.Writer) {
fmt.Fprint(w, strconv.Quote(e.String()))
}
type NotificationType string type NotificationType string
const ( const (

View File

@ -7,13 +7,6 @@ import (
"github.com/viktorstrate/photoview/api/utils" "github.com/viktorstrate/photoview/api/utils"
) )
type MediaType string
const (
MediaTypePhoto MediaType = "photo"
MediaTypeVide MediaType = "video"
)
type Media struct { type Media struct {
MediaID int MediaID int
Title string Title string
@ -64,7 +57,7 @@ func NewMediaFromRows(rows *sql.Rows) ([]*Media, error) {
for rows.Next() { for rows.Next() {
var media Media var media Media
if err := rows.Scan(&media.MediaID, &media.Title, &media.Path, &media.PathHash, &media.AlbumId, &media.ExifId, &media.Favorite); err != nil { if err := rows.Scan(&media.MediaID, &media.Title, &media.Path, &media.PathHash, &media.AlbumId, &media.ExifId, &media.Favorite, &media.Type); err != nil {
return nil, err return nil, err
} }
medias = append(medias, &media) medias = append(medias, &media)

View File

@ -132,14 +132,18 @@ func (r *mediaResolver) HighRes(ctx context.Context, obj *models.Media) (*models
url, err := models.NewMediaURLFromRow(row) url, err := models.NewMediaURLFromRow(row)
if err != nil { if err != nil {
return nil, errors.Wrapf(err, "could not query high-res (%s)", obj.Path) if err == sql.ErrNoRows {
return nil, nil
} else {
return nil, errors.Wrapf(err, "could not query high-res (%s)", obj.Path)
}
} }
return url, nil return url, nil
} }
func (r *mediaResolver) Thumbnail(ctx context.Context, obj *models.Media) (*models.MediaURL, error) { func (r *mediaResolver) Thumbnail(ctx context.Context, obj *models.Media) (*models.MediaURL, error) {
row := r.Database.QueryRow("SELECT * FROM media_url WHERE media_id = ? AND purpose = ?", obj.MediaID, models.PhotoThumbnail) row := r.Database.QueryRow("SELECT * FROM media_url WHERE media_id = ? AND (purpose = ? OR purpose = ?)", obj.MediaID, models.PhotoThumbnail, models.VideoThumbnail)
url, err := models.NewMediaURLFromRow(row) url, err := models.NewMediaURLFromRow(row)
if err != nil { if err != nil {

View File

@ -198,6 +198,11 @@ type MediaDownload {
url: String! url: String!
} }
enum MediaType {
photo
video
}
type Media { type Media {
id: Int! id: Int!
title: String! title: String!
@ -211,6 +216,7 @@ type Media {
album: Album! album: Album!
exif: MediaEXIF exif: MediaEXIF
favorite: Boolean! favorite: Boolean!
type: MediaType!
shares: [ShareToken!]! shares: [ShareToken!]!
downloads: [MediaDownload!]! downloads: [MediaDownload!]!

View File

@ -132,7 +132,7 @@ func RegisterPhotoRoutes(db *sql.DB, router *mux.Router) {
var cachedPath string var cachedPath string
var file *os.File = nil var file *os.File = nil
if purpose == models.PhotoThumbnail || purpose == models.PhotoHighRes { if purpose == models.PhotoThumbnail || purpose == models.PhotoHighRes || purpose == models.VideoThumbnail {
cachedPath = path.Join(scanner.PhotoCache(), strconv.Itoa(media.AlbumId), strconv.Itoa(media_id), media_name) cachedPath = path.Join(scanner.PhotoCache(), strconv.Itoa(media.AlbumId), strconv.Itoa(media_id), media_name)
} }

View File

@ -104,7 +104,7 @@ func (queue *ScannerQueue) startBackgroundWorker() {
notification.BroadcastNotification(&models.Notification{ notification.BroadcastNotification(&models.Notification{
Key: "global-scanner-progress", Key: "global-scanner-progress",
Type: models.NotificationTypeMessage, Type: models.NotificationTypeMessage,
Header: fmt.Sprintf("Scanning photos"), Header: fmt.Sprintf("Scanning media"),
Content: fmt.Sprintf("%d jobs in progress\n%d jobs waiting", in_progress_length, up_next_length), Content: fmt.Sprintf("%d jobs in progress\n%d jobs waiting", in_progress_length, up_next_length),
}) })
}) })

View File

@ -25,14 +25,14 @@ func scanAlbum(album *models.Album, cache *AlbumScannerCache, db *sql.DB) {
notification.BroadcastNotification(&models.Notification{ notification.BroadcastNotification(&models.Notification{
Key: album_notify_key, Key: album_notify_key,
Type: models.NotificationTypeMessage, Type: models.NotificationTypeMessage,
Header: fmt.Sprintf("Found new photos in album '%s'", album.Title), Header: fmt.Sprintf("Found new media in album '%s'", album.Title),
Content: fmt.Sprintf("Found photo %s", photo.Path), Content: fmt.Sprintf("Found %s", photo.Path),
}) })
}) })
} }
}) })
if err != nil { if err != nil {
ScannerError("Failed to find photos for album (%s): %s", album.Path, err) ScannerError("Failed to find media for album (%s): %s", album.Path, err)
} }
album_has_changes := false album_has_changes := false
@ -55,8 +55,8 @@ func scanAlbum(album *models.Album, cache *AlbumScannerCache, db *sql.DB) {
notification.BroadcastNotification(&models.Notification{ notification.BroadcastNotification(&models.Notification{
Key: album_notify_key, Key: album_notify_key,
Type: models.NotificationTypeProgress, Type: models.NotificationTypeProgress,
Header: fmt.Sprintf("Processing photo for album '%s'", album.Title), Header: fmt.Sprintf("Processing media for album '%s'", album.Title),
Content: fmt.Sprintf("Processed photo at %s", photo.Path), Content: fmt.Sprintf("Processed media at %s", photo.Path),
Progress: &progress, Progress: &progress,
}) })
} }
@ -73,8 +73,8 @@ func scanAlbum(album *models.Album, cache *AlbumScannerCache, db *sql.DB) {
Key: album_notify_key, Key: album_notify_key,
Type: models.NotificationTypeMessage, Type: models.NotificationTypeMessage,
Positive: true, Positive: true,
Header: fmt.Sprintf("Done processing photos for album '%s'", album.Title), Header: fmt.Sprintf("Done processing media for album '%s'", album.Title),
Content: fmt.Sprintf("All photos have been processed"), Content: fmt.Sprintf("All media have been processed"),
Timeout: &timeoutDelay, Timeout: &timeoutDelay,
}) })
} }

View File

@ -18,7 +18,7 @@ func ScanMedia(tx *sql.Tx, mediaPath string, albumId int, cache *AlbumScannerCac
photo, err := models.NewMediaFromRow(row) photo, err := models.NewMediaFromRow(row)
if err != sql.ErrNoRows { if err != sql.ErrNoRows {
if err == nil { if err == nil {
log.Printf("Image already scanned: %s\n", mediaPath) log.Printf("Media already scanned: %s\n", mediaPath)
return photo, false, nil return photo, false, nil
} else { } else {
return nil, false, errors.Wrap(err, "scan media fetch from database") return nil, false, errors.Wrap(err, "scan media fetch from database")