diff --git a/api/graphql/generated.go b/api/graphql/generated.go index 748d7fdb..6a60718d 100644 --- a/api/graphql/generated.go +++ b/api/graphql/generated.go @@ -130,6 +130,7 @@ type ComplexityRoot struct { Camera func(childComplexity int) int Coordinates func(childComplexity int) int DateShot func(childComplexity int) int + Description func(childComplexity int) int Exposure func(childComplexity int) int ExposureProgram func(childComplexity int) int Flash func(childComplexity int) int @@ -739,6 +740,13 @@ func (e *executableSchema) Complexity(typeName, field string, childComplexity in return e.complexity.MediaEXIF.DateShot(childComplexity), true + case "MediaEXIF.description": + if e.complexity.MediaEXIF.Description == nil { + break + } + + return e.complexity.MediaEXIF.Description(childComplexity), true + case "MediaEXIF.exposure": if e.complexity.MediaEXIF.Exposure == nil { break @@ -2088,6 +2096,8 @@ type Media { type MediaEXIF { id: ID! media: Media! + "The description of the image" + description: String "The model name of the camera" camera: String "The maker of the camera" @@ -4754,6 +4764,38 @@ func (ec *executionContext) _MediaEXIF_media(ctx context.Context, field graphql. return ec.marshalNMedia2ᚖgithubᚗcomᚋphotoviewᚋphotoviewᚋapiᚋgraphqlᚋmodelsᚐMedia(ctx, field.Selections, res) } +func (ec *executionContext) _MediaEXIF_description(ctx context.Context, field graphql.CollectedField, obj *models.MediaEXIF) (ret graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + fc := &graphql.FieldContext{ + Object: "MediaEXIF", + Field: field, + Args: nil, + IsMethod: false, + IsResolver: 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.Description, nil + }) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + func (ec *executionContext) _MediaEXIF_camera(ctx context.Context, field graphql.CollectedField, obj *models.MediaEXIF) (ret graphql.Marshaler) { defer func() { if r := recover(); r != nil { @@ -11377,6 +11419,13 @@ func (ec *executionContext) _MediaEXIF(ctx context.Context, sel ast.SelectionSet if out.Values[i] == graphql.Null { invalids++ } + case "description": + innerFunc := func(ctx context.Context) (res graphql.Marshaler) { + return ec._MediaEXIF_description(ctx, field, obj) + } + + out.Values[i] = innerFunc(ctx) + case "camera": innerFunc := func(ctx context.Context) (res graphql.Marshaler) { return ec._MediaEXIF_camera(ctx, field, obj) diff --git a/api/graphql/models/media_exif.go b/api/graphql/models/media_exif.go index 37af1e47..c056ee8b 100644 --- a/api/graphql/models/media_exif.go +++ b/api/graphql/models/media_exif.go @@ -6,6 +6,7 @@ import ( type MediaEXIF struct { Model + Description *string Camera *string Maker *string Lens *string diff --git a/api/graphql/schema.graphql b/api/graphql/schema.graphql index 8e4f420f..0ece4fb4 100644 --- a/api/graphql/schema.graphql +++ b/api/graphql/schema.graphql @@ -382,6 +382,8 @@ type Media { type MediaEXIF { id: ID! media: Media! + "The description of the image" + description: String "The model name of the camera" camera: String "The maker of the camera" diff --git a/api/scanner/exif/exif_parser_external.go b/api/scanner/exif/exif_parser_external.go index aef14ebb..d6da190d 100644 --- a/api/scanner/exif/exif_parser_external.go +++ b/api/scanner/exif/exif_parser_external.go @@ -81,6 +81,13 @@ func (p *externalExifParser) ParseExif(media_path string) (returnExif *models.Me newExif := models.MediaEXIF{} found_exif := false + // Get description + description, err := fileInfo.GetString("ImageDescription") + if err == nil { + found_exif = true + newExif.Description = &description + } + // Get camera model model, err := fileInfo.GetString("Model") if err == nil { diff --git a/api/scanner/exif/exif_parser_internal.go b/api/scanner/exif/exif_parser_internal.go index 11c8ef80..4244b86d 100644 --- a/api/scanner/exif/exif_parser_internal.go +++ b/api/scanner/exif/exif_parser_internal.go @@ -44,6 +44,11 @@ func (p internalExifParser) ParseExif(media_path string) (returnExif *models.Med newExif := models.MediaEXIF{} + description, err := p.readStringTag(exifTags, exif.ImageDescription, media_path) + if err == nil { + newExif.Description = description + } + model, err := p.readStringTag(exifTags, exif.Model, media_path) if err == nil { newExif.Camera = model diff --git a/api/scanner/exif/exif_test.go b/api/scanner/exif/exif_test.go index 9c2d32a8..ca0ae43d 100644 --- a/api/scanner/exif/exif_test.go +++ b/api/scanner/exif/exif_test.go @@ -48,6 +48,7 @@ func TestExifParsers(t *testing.T) { { path: "./test_data/bird.jpg", assert: func(t *testing.T, exif *models.MediaEXIF) { + assert.EqualValues(t, *exif.Description, "Photo of a Bird") assert.WithinDuration(t, *exif.DateShot, time.Unix(1336318784, 0).UTC(), time.Minute) assert.EqualValues(t, *exif.Camera, "Canon EOS 600D") assert.EqualValues(t, *exif.Maker, "Canon") diff --git a/api/scanner/exif/test_data/bird.jpg b/api/scanner/exif/test_data/bird.jpg index ea631f9e..e7175428 100644 Binary files a/api/scanner/exif/test_data/bird.jpg and b/api/scanner/exif/test_data/bird.jpg differ diff --git a/ui/src/Pages/SharePage/AlbumSharePage.tsx b/ui/src/Pages/SharePage/AlbumSharePage.tsx index 063a5a34..0e6f5da8 100644 --- a/ui/src/Pages/SharePage/AlbumSharePage.tsx +++ b/ui/src/Pages/SharePage/AlbumSharePage.tsx @@ -68,6 +68,7 @@ export const SHARE_ALBUM_QUERY = gql` } exif { id + description camera maker lens diff --git a/ui/src/Pages/SharePage/SharePage.tsx b/ui/src/Pages/SharePage/SharePage.tsx index 4828e263..d49967c5 100644 --- a/ui/src/Pages/SharePage/SharePage.tsx +++ b/ui/src/Pages/SharePage/SharePage.tsx @@ -49,6 +49,7 @@ export const SHARE_TOKEN_QUERY = gql` } exif { id + description camera maker lens diff --git a/ui/src/Pages/SharePage/__generated__/SharePageToken.ts b/ui/src/Pages/SharePage/__generated__/SharePageToken.ts index dd4f8716..aff5a897 100644 --- a/ui/src/Pages/SharePage/__generated__/SharePageToken.ts +++ b/ui/src/Pages/SharePage/__generated__/SharePageToken.ts @@ -106,6 +106,10 @@ export interface SharePageToken_shareToken_media_exif_coordinates { export interface SharePageToken_shareToken_media_exif { __typename: 'MediaEXIF' id: string + /** + * The description of the image + */ + description: string | null /** * The model name of the camera */ diff --git a/ui/src/Pages/SharePage/__generated__/shareAlbumQuery.ts b/ui/src/Pages/SharePage/__generated__/shareAlbumQuery.ts index 26b476e0..344e0512 100644 --- a/ui/src/Pages/SharePage/__generated__/shareAlbumQuery.ts +++ b/ui/src/Pages/SharePage/__generated__/shareAlbumQuery.ts @@ -120,6 +120,10 @@ export interface shareAlbumQuery_album_media_exif_coordinates { export interface shareAlbumQuery_album_media_exif { __typename: 'MediaEXIF' id: string + /** + * The description of the image + */ + description: string | null /** * The model name of the camera */ diff --git a/ui/src/components/sidebar/MediaSidebar/MediaSidebar.tsx b/ui/src/components/sidebar/MediaSidebar/MediaSidebar.tsx index f5bce879..64aa963f 100644 --- a/ui/src/components/sidebar/MediaSidebar/MediaSidebar.tsx +++ b/ui/src/components/sidebar/MediaSidebar/MediaSidebar.tsx @@ -65,6 +65,7 @@ export const SIDEBAR_MEDIA_QUERY = gql` } exif { id + description camera maker lens diff --git a/ui/src/components/sidebar/MediaSidebar/MediaSidebarExif.test.tsx b/ui/src/components/sidebar/MediaSidebar/MediaSidebarExif.test.tsx index 0e3b0026..d0e1b833 100644 --- a/ui/src/components/sidebar/MediaSidebar/MediaSidebarExif.test.tsx +++ b/ui/src/components/sidebar/MediaSidebar/MediaSidebarExif.test.tsx @@ -12,6 +12,7 @@ describe('ExifDetails', () => { type: MediaType.Photo, exif: { id: '0', + description: null, camera: null, maker: null, lens: null, @@ -30,6 +31,7 @@ describe('ExifDetails', () => { render() + expect(screen.queryByText('Description')).not.toBeInTheDocument() expect(screen.queryByText('Camera')).not.toBeInTheDocument() expect(screen.queryByText('Maker')).not.toBeInTheDocument() expect(screen.queryByText('Lens')).not.toBeInTheDocument() @@ -50,6 +52,7 @@ describe('ExifDetails', () => { type: MediaType.Photo, exif: { id: '1666', + description: "Media description", camera: 'Canon EOS R', maker: 'Canon', lens: 'TAMRON SP 24-70mm F/2.8', @@ -72,6 +75,8 @@ describe('ExifDetails', () => { render() + expect(screen.getByText('Description')).toBeInTheDocument() + expect(screen.getByText('Camera')).toBeInTheDocument() expect(screen.getByText('Canon EOS R')).toBeInTheDocument() diff --git a/ui/src/components/sidebar/MediaSidebar/MediaSidebarExif.tsx b/ui/src/components/sidebar/MediaSidebar/MediaSidebarExif.tsx index 12adeafd..0c243f6d 100644 --- a/ui/src/components/sidebar/MediaSidebar/MediaSidebarExif.tsx +++ b/ui/src/components/sidebar/MediaSidebar/MediaSidebarExif.tsx @@ -120,6 +120,7 @@ const ExifDetails = ({ media }: ExifDetailsProps) => { } const exifNameLookup = (t: TranslationFn): { [key: string]: string } => ({ + description: t('sidebar.media.exif.description', 'Description'), camera: t('sidebar.media.exif.name.camera', 'Camera'), maker: t('sidebar.media.exif.name.maker', 'Maker'), lens: t('sidebar.media.exif.name.lens', 'Lens'), diff --git a/ui/src/components/sidebar/MediaSidebar/__generated__/sidebarMediaQuery.ts b/ui/src/components/sidebar/MediaSidebar/__generated__/sidebarMediaQuery.ts index 0bd4ce20..8cadd6eb 100644 --- a/ui/src/components/sidebar/MediaSidebar/__generated__/sidebarMediaQuery.ts +++ b/ui/src/components/sidebar/MediaSidebar/__generated__/sidebarMediaQuery.ts @@ -85,6 +85,10 @@ export interface sidebarMediaQuery_media_exif_coordinates { export interface sidebarMediaQuery_media_exif { __typename: 'MediaEXIF' id: string + /** + * The description of the image + */ + description: string | null /** * The model name of the camera */