mirror of
https://github.com/photoprism/photoprism.git
synced 2025-12-12 00:34:13 +01:00
API: Rename /batch/photos endpoint to /batch/photos/edit #271
Signed-off-by: Michael Mayer <michael@photoprism.app>
This commit is contained in:
@@ -3,7 +3,8 @@ package batch
|
||||
type Action = string
|
||||
|
||||
const (
|
||||
ActionNone Action = "none"
|
||||
ActionUpdate Action = "update"
|
||||
ActionAdd Action = "add"
|
||||
ActionRemove Action = "remove"
|
||||
ActionKeep Action = "keep"
|
||||
ActionChange Action = "change"
|
||||
)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
package batch
|
||||
|
||||
import (
|
||||
"github.com/photoprism/photoprism/internal/entity"
|
||||
"github.com/photoprism/photoprism/internal/entity/search"
|
||||
)
|
||||
|
||||
// PhotoForm represents photo batch edit form values.
|
||||
type PhotoForm struct {
|
||||
// PhotosForm represents photo batch edit form values.
|
||||
type PhotosForm struct {
|
||||
PhotoType String `json:"Type"`
|
||||
PhotoTitle String `json:"Title"`
|
||||
PhotoCaption String `json:"Caption"`
|
||||
@@ -30,207 +30,223 @@ type PhotoForm struct {
|
||||
CameraID UInt `json:"CameraID"`
|
||||
LensID UInt `json:"LensID"`
|
||||
|
||||
DetailsSubject String `json:"Subject"`
|
||||
DetailsArtist String `json:"Artist"`
|
||||
DetailsCopyright String `json:"Copyright"`
|
||||
DetailsLicense String `json:"License"`
|
||||
DetailsKeywords String `json:"DetailsKeywords"`
|
||||
DetailsSubject String `json:"DetailsSubject"`
|
||||
DetailsArtist String `json:"DetailsArtist"`
|
||||
DetailsCopyright String `json:"DetailsCopyright"`
|
||||
DetailsLicense String `json:"DetailsLicense"`
|
||||
}
|
||||
|
||||
func NewPhotoForm(photos entity.Photos) *PhotoForm {
|
||||
frm := &PhotoForm{}
|
||||
func NewPhotosForm(photos search.PhotoResults) *PhotosForm {
|
||||
frm := &PhotosForm{}
|
||||
|
||||
for _, photo := range photos {
|
||||
if photo.PhotoType != "" && frm.PhotoType.Value == "" {
|
||||
for i, photo := range photos {
|
||||
if i == 0 {
|
||||
frm.PhotoType.Value = photo.PhotoType
|
||||
frm.PhotoType.Matches = true
|
||||
} else if photo.PhotoType != frm.PhotoType.Value {
|
||||
frm.PhotoType.Matches = false
|
||||
frm.PhotoType.Mixed = true
|
||||
frm.PhotoType.Value = ""
|
||||
}
|
||||
|
||||
if photo.PhotoTitle != "" && frm.PhotoTitle.Value == "" {
|
||||
if i == 0 {
|
||||
frm.PhotoTitle.Value = photo.PhotoTitle
|
||||
frm.PhotoTitle.Matches = true
|
||||
} else if photo.PhotoTitle != frm.PhotoTitle.Value {
|
||||
frm.PhotoTitle.Matches = false
|
||||
frm.PhotoTitle.Mixed = true
|
||||
frm.PhotoTitle.Value = ""
|
||||
}
|
||||
|
||||
if photo.PhotoCaption != "" && frm.PhotoCaption.Value == "" {
|
||||
if i == 0 {
|
||||
frm.PhotoCaption.Value = photo.PhotoCaption
|
||||
frm.PhotoTitle.Matches = true
|
||||
} else if photo.PhotoCaption != frm.PhotoCaption.Value {
|
||||
frm.PhotoCaption.Matches = false
|
||||
frm.PhotoCaption.Mixed = true
|
||||
frm.PhotoCaption.Value = ""
|
||||
}
|
||||
|
||||
if !photo.TakenAt.IsZero() && frm.TakenAt.Value.IsZero() {
|
||||
if i == 0 {
|
||||
frm.TakenAt.Value = photo.TakenAt
|
||||
frm.TakenAt.Matches = true
|
||||
} else if photo.TakenAt != frm.TakenAt.Value {
|
||||
frm.TakenAt.Matches = false
|
||||
frm.TakenAt.Mixed = true
|
||||
}
|
||||
|
||||
if !photo.TakenAtLocal.IsZero() && frm.TakenAtLocal.Value.IsZero() {
|
||||
if i == 0 {
|
||||
frm.TakenAtLocal.Value = photo.TakenAtLocal
|
||||
frm.TakenAtLocal.Matches = true
|
||||
} else if photo.TakenAtLocal != frm.TakenAtLocal.Value {
|
||||
frm.TakenAtLocal.Matches = false
|
||||
frm.TakenAtLocal.Mixed = true
|
||||
}
|
||||
|
||||
if photo.PhotoDay > 0 && frm.PhotoDay.Value == 0 {
|
||||
if i == 0 {
|
||||
frm.PhotoDay.Value = photo.PhotoDay
|
||||
frm.PhotoDay.Matches = true
|
||||
} else if photo.PhotoDay != frm.PhotoDay.Value {
|
||||
frm.PhotoDay.Matches = false
|
||||
frm.PhotoDay.Mixed = true
|
||||
frm.PhotoDay.Value = 0
|
||||
}
|
||||
|
||||
if photo.PhotoMonth > 0 && frm.PhotoMonth.Value == 0 {
|
||||
if i == 0 {
|
||||
frm.PhotoMonth.Value = photo.PhotoMonth
|
||||
frm.PhotoMonth.Matches = true
|
||||
} else if photo.PhotoMonth != frm.PhotoMonth.Value {
|
||||
frm.PhotoMonth.Matches = false
|
||||
frm.PhotoMonth.Mixed = true
|
||||
frm.PhotoMonth.Value = 0
|
||||
}
|
||||
|
||||
if photo.PhotoYear > 0 && frm.PhotoYear.Value == 0 {
|
||||
if i == 0 {
|
||||
frm.PhotoYear.Value = photo.PhotoYear
|
||||
frm.PhotoYear.Matches = true
|
||||
} else if photo.PhotoYear != frm.PhotoYear.Value {
|
||||
frm.PhotoYear.Matches = false
|
||||
frm.PhotoYear.Mixed = true
|
||||
frm.PhotoYear.Value = 0
|
||||
}
|
||||
|
||||
if photo.TimeZone != "" && frm.TimeZone.Value == "" {
|
||||
if i == 0 {
|
||||
frm.TimeZone.Value = photo.TimeZone
|
||||
frm.TimeZone.Matches = true
|
||||
} else if photo.TimeZone != frm.TimeZone.Value {
|
||||
frm.TimeZone.Matches = false
|
||||
frm.TimeZone.Mixed = true
|
||||
frm.TimeZone.Value = "Local"
|
||||
}
|
||||
|
||||
if photo.PhotoCountry != "" && frm.PhotoCountry.Value == "" {
|
||||
if i == 0 {
|
||||
frm.PhotoCountry.Value = photo.PhotoCountry
|
||||
frm.PhotoCountry.Matches = true
|
||||
} else if photo.PhotoCountry != frm.PhotoCountry.Value {
|
||||
frm.PhotoCountry.Matches = false
|
||||
frm.PhotoCountry.Mixed = true
|
||||
frm.PhotoCountry.Value = "zz"
|
||||
}
|
||||
|
||||
if photo.PhotoAltitude != 0 && frm.PhotoAltitude.Value == 0 {
|
||||
if i == 0 {
|
||||
frm.PhotoAltitude.Value = photo.PhotoAltitude
|
||||
frm.PhotoAltitude.Matches = true
|
||||
} else if photo.PhotoAltitude != frm.PhotoAltitude.Value {
|
||||
frm.PhotoAltitude.Matches = false
|
||||
frm.PhotoAltitude.Mixed = true
|
||||
frm.PhotoAltitude.Value = 0
|
||||
}
|
||||
|
||||
if photo.PhotoLat != 0.0 && frm.PhotoLat.Value == 0.0 {
|
||||
if i == 0 {
|
||||
frm.PhotoLat.Value = photo.PhotoLat
|
||||
frm.PhotoLat.Matches = true
|
||||
} else if photo.PhotoLat != frm.PhotoLat.Value {
|
||||
frm.PhotoLat.Matches = false
|
||||
frm.PhotoLat.Mixed = true
|
||||
frm.PhotoLat.Value = 0.0
|
||||
}
|
||||
|
||||
if photo.PhotoLng != 0.0 && frm.PhotoLng.Value == 0.0 {
|
||||
if i == 0 {
|
||||
frm.PhotoLng.Value = photo.PhotoLng
|
||||
frm.PhotoLng.Matches = true
|
||||
} else if photo.PhotoLng != frm.PhotoLng.Value {
|
||||
frm.PhotoLng.Matches = false
|
||||
frm.PhotoLng.Mixed = false
|
||||
frm.PhotoLng.Value = 0.0
|
||||
}
|
||||
|
||||
if photo.PhotoIso != 0 && frm.PhotoIso.Value == 0 {
|
||||
if i == 0 {
|
||||
frm.PhotoIso.Value = photo.PhotoIso
|
||||
frm.PhotoIso.Matches = true
|
||||
} else if photo.PhotoIso != frm.PhotoIso.Value {
|
||||
frm.PhotoIso.Matches = false
|
||||
frm.PhotoIso.Mixed = true
|
||||
frm.PhotoIso.Value = 0
|
||||
}
|
||||
|
||||
if photo.PhotoFocalLength != 0 && frm.PhotoFocalLength.Value == 0 {
|
||||
if i == 0 {
|
||||
frm.PhotoFocalLength.Value = photo.PhotoFocalLength
|
||||
frm.PhotoFocalLength.Matches = true
|
||||
} else if photo.PhotoFocalLength != frm.PhotoFocalLength.Value {
|
||||
frm.PhotoFocalLength.Matches = false
|
||||
frm.PhotoFocalLength.Mixed = true
|
||||
frm.PhotoFocalLength.Value = 0
|
||||
}
|
||||
|
||||
if photo.PhotoFNumber != 0.0 && frm.PhotoFNumber.Value == 0.0 {
|
||||
if i == 0 {
|
||||
frm.PhotoFNumber.Value = photo.PhotoFNumber
|
||||
frm.PhotoFNumber.Matches = true
|
||||
} else if photo.PhotoFNumber != frm.PhotoFNumber.Value {
|
||||
frm.PhotoFNumber.Matches = false
|
||||
frm.PhotoFNumber.Mixed = true
|
||||
frm.PhotoFNumber.Value = 0
|
||||
}
|
||||
|
||||
if photo.PhotoExposure != "" && frm.PhotoExposure.Value == "" {
|
||||
if i == 0 {
|
||||
frm.PhotoExposure.Value = photo.PhotoExposure
|
||||
frm.PhotoExposure.Matches = true
|
||||
} else if photo.PhotoExposure != frm.PhotoExposure.Value {
|
||||
frm.PhotoExposure.Matches = false
|
||||
frm.PhotoExposure.Mixed = true
|
||||
frm.PhotoExposure.Value = ""
|
||||
}
|
||||
|
||||
if photo.PhotoFavorite && !frm.PhotoFavorite.Value {
|
||||
if i == 0 {
|
||||
frm.PhotoFavorite.Value = photo.PhotoFavorite
|
||||
frm.PhotoFavorite.Matches = true
|
||||
} else if photo.PhotoFavorite != frm.PhotoFavorite.Value {
|
||||
frm.PhotoFavorite.Matches = false
|
||||
frm.PhotoFavorite.Mixed = true
|
||||
frm.PhotoFavorite.Value = false
|
||||
}
|
||||
|
||||
if photo.PhotoPrivate && !frm.PhotoPrivate.Value {
|
||||
if i == 0 {
|
||||
frm.PhotoPrivate.Value = photo.PhotoPrivate
|
||||
frm.PhotoPrivate.Matches = true
|
||||
} else if photo.PhotoPrivate != frm.PhotoPrivate.Value {
|
||||
frm.PhotoPrivate.Matches = false
|
||||
frm.PhotoPrivate.Mixed = true
|
||||
frm.PhotoPrivate.Value = false
|
||||
}
|
||||
|
||||
if photo.PhotoScan && !frm.PhotoScan.Value {
|
||||
if i == 0 {
|
||||
frm.PhotoScan.Value = photo.PhotoScan
|
||||
frm.PhotoScan.Matches = true
|
||||
} else if photo.PhotoScan != frm.PhotoScan.Value {
|
||||
frm.PhotoScan.Matches = false
|
||||
frm.PhotoScan.Mixed = true
|
||||
frm.PhotoScan.Value = false
|
||||
}
|
||||
|
||||
if photo.PhotoPanorama && !frm.PhotoPanorama.Value {
|
||||
if i == 0 {
|
||||
frm.PhotoPanorama.Value = photo.PhotoPanorama
|
||||
frm.PhotoPanorama.Matches = true
|
||||
} else if photo.PhotoPanorama != frm.PhotoPanorama.Value {
|
||||
frm.PhotoPanorama.Matches = false
|
||||
frm.PhotoPanorama.Mixed = true
|
||||
frm.PhotoPanorama.Value = false
|
||||
}
|
||||
|
||||
if photo.CameraID != 0 && frm.CameraID.Value == 0 {
|
||||
if i == 0 {
|
||||
frm.CameraID.Value = photo.CameraID
|
||||
frm.CameraID.Matches = true
|
||||
} else if photo.CameraID != frm.CameraID.Value {
|
||||
frm.CameraID.Matches = false
|
||||
frm.CameraID.Mixed = true
|
||||
frm.CameraID.Value = 1
|
||||
}
|
||||
|
||||
if photo.LensID != 0 && frm.LensID.Value == 0 {
|
||||
if i == 0 {
|
||||
frm.LensID.Value = photo.LensID
|
||||
frm.LensID.Matches = true
|
||||
} else if photo.LensID != frm.LensID.Value {
|
||||
frm.LensID.Matches = false
|
||||
frm.LensID.Mixed = true
|
||||
frm.LensID.Value = 1
|
||||
}
|
||||
|
||||
if photo.Details != nil {
|
||||
if photo.Details.Subject != "" && frm.DetailsSubject.Value == "" {
|
||||
frm.DetailsSubject.Value = photo.Details.Subject
|
||||
frm.DetailsSubject.Matches = true
|
||||
} else if photo.Details.Subject != frm.DetailsSubject.Value {
|
||||
frm.DetailsSubject.Matches = false
|
||||
}
|
||||
|
||||
if photo.Details.Artist != "" && frm.DetailsArtist.Value == "" {
|
||||
frm.DetailsArtist.Value = photo.Details.Artist
|
||||
frm.DetailsArtist.Matches = true
|
||||
} else if photo.Details.Artist != frm.DetailsArtist.Value {
|
||||
frm.DetailsArtist.Matches = false
|
||||
}
|
||||
|
||||
if photo.Details.Copyright != "" && frm.DetailsCopyright.Value == "" {
|
||||
frm.DetailsCopyright.Value = photo.Details.Copyright
|
||||
frm.DetailsCopyright.Matches = true
|
||||
} else if photo.Details.Copyright != frm.DetailsCopyright.Value {
|
||||
frm.DetailsCopyright.Matches = false
|
||||
}
|
||||
|
||||
if photo.Details.License != "" && frm.DetailsLicense.Value == "" {
|
||||
frm.DetailsLicense.Value = photo.Details.License
|
||||
frm.DetailsLicense.Matches = true
|
||||
} else if photo.Details.License != frm.DetailsLicense.Value {
|
||||
frm.DetailsLicense.Matches = false
|
||||
}
|
||||
if i == 0 {
|
||||
frm.DetailsKeywords.Value = photo.DetailsKeywords
|
||||
} else if photo.DetailsKeywords != frm.DetailsKeywords.Value {
|
||||
frm.DetailsKeywords.Mixed = true
|
||||
frm.DetailsKeywords.Value = ""
|
||||
}
|
||||
|
||||
if i == 0 {
|
||||
frm.DetailsSubject.Value = photo.DetailsSubject
|
||||
} else if photo.DetailsSubject != frm.DetailsSubject.Value {
|
||||
frm.DetailsSubject.Mixed = true
|
||||
frm.DetailsSubject.Value = ""
|
||||
}
|
||||
|
||||
if i == 0 {
|
||||
frm.DetailsArtist.Value = photo.DetailsArtist
|
||||
} else if photo.DetailsArtist != frm.DetailsArtist.Value {
|
||||
frm.DetailsArtist.Mixed = true
|
||||
frm.DetailsArtist.Value = ""
|
||||
}
|
||||
|
||||
if i == 0 {
|
||||
frm.DetailsCopyright.Value = photo.DetailsCopyright
|
||||
} else if photo.DetailsCopyright != frm.DetailsCopyright.Value {
|
||||
frm.DetailsCopyright.Mixed = true
|
||||
frm.DetailsCopyright.Value = ""
|
||||
}
|
||||
|
||||
if i == 0 {
|
||||
frm.DetailsLicense.Value = photo.DetailsLicense
|
||||
} else if photo.DetailsLicense != frm.DetailsLicense.Value {
|
||||
frm.DetailsLicense.Mixed = true
|
||||
frm.DetailsLicense.Value = ""
|
||||
}
|
||||
}
|
||||
|
||||
// Use defaults for the following values if they are empty:
|
||||
if frm.PhotoCountry.Value == "" {
|
||||
frm.PhotoCountry.Value = "zz"
|
||||
}
|
||||
|
||||
if frm.CameraID.Value < 1 {
|
||||
frm.CameraID.Value = 1
|
||||
}
|
||||
|
||||
if frm.LensID.Value < 1 {
|
||||
frm.LensID.Value = 1
|
||||
}
|
||||
|
||||
return frm
|
||||
|
||||
61
internal/form/batch/photos_test.go
Normal file
61
internal/form/batch/photos_test.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package batch
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/photoprism/photoprism/internal/entity/search"
|
||||
"github.com/photoprism/photoprism/pkg/fs"
|
||||
)
|
||||
|
||||
func TestNewPhotosForm(t *testing.T) {
|
||||
t.Run("Success", func(t *testing.T) {
|
||||
var photos search.PhotoResults
|
||||
|
||||
dataFile := fs.Abs("./testdata/photos.json")
|
||||
data, dataErr := os.ReadFile(dataFile)
|
||||
|
||||
if dataErr != nil {
|
||||
t.Fatal(dataErr)
|
||||
}
|
||||
|
||||
jsonErr := json.Unmarshal(data, &photos)
|
||||
|
||||
if jsonErr != nil {
|
||||
t.Fatal(jsonErr)
|
||||
}
|
||||
|
||||
frm := NewPhotosForm(photos)
|
||||
|
||||
// Photo metadata.
|
||||
assert.Equal(t, "", frm.PhotoType.Value)
|
||||
assert.Equal(t, true, frm.PhotoType.Mixed)
|
||||
assert.Equal(t, "", frm.PhotoTitle.Value)
|
||||
assert.Equal(t, true, frm.PhotoTitle.Mixed)
|
||||
assert.Equal(t, "", frm.PhotoCaption.Value)
|
||||
assert.Equal(t, true, frm.PhotoCaption.Mixed)
|
||||
assert.Equal(t, false, frm.PhotoFavorite.Value)
|
||||
assert.Equal(t, true, frm.PhotoFavorite.Mixed)
|
||||
assert.Equal(t, false, frm.PhotoPrivate.Value)
|
||||
assert.Equal(t, false, frm.PhotoPrivate.Mixed)
|
||||
assert.Equal(t, uint(1000003), frm.CameraID.Value)
|
||||
assert.Equal(t, false, frm.CameraID.Mixed)
|
||||
assert.Equal(t, uint(1000000), frm.LensID.Value)
|
||||
assert.Equal(t, false, frm.LensID.Mixed)
|
||||
|
||||
// Additional details.
|
||||
assert.Equal(t, "", frm.DetailsKeywords.Value)
|
||||
assert.Equal(t, true, frm.DetailsKeywords.Mixed)
|
||||
assert.Equal(t, "", frm.DetailsSubject.Value)
|
||||
assert.Equal(t, true, frm.DetailsSubject.Mixed)
|
||||
assert.Equal(t, "", frm.DetailsArtist.Value)
|
||||
assert.Equal(t, true, frm.DetailsArtist.Mixed)
|
||||
assert.Equal(t, "", frm.DetailsCopyright.Value)
|
||||
assert.Equal(t, true, frm.DetailsCopyright.Mixed)
|
||||
assert.Equal(t, "", frm.DetailsLicense.Value)
|
||||
assert.Equal(t, true, frm.DetailsLicense.Mixed)
|
||||
})
|
||||
}
|
||||
31
internal/form/batch/selection.go
Normal file
31
internal/form/batch/selection.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package batch
|
||||
|
||||
import "strings"
|
||||
|
||||
// PhotosRequest represents items selected in the user interface.
|
||||
type PhotosRequest struct {
|
||||
Return bool `json:"return,omitempty"`
|
||||
Filter string `json:"filter,omitempty"`
|
||||
Photos []string `json:"photos"`
|
||||
Values *PhotosForm `json:"values,omitempty"`
|
||||
}
|
||||
|
||||
// Empty checks if any specific items were selected.
|
||||
func (f PhotosRequest) Empty() bool {
|
||||
switch {
|
||||
case len(f.Photos) > 0:
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// Get returns a string slice with the selected item UIDs.
|
||||
func (f PhotosRequest) Get() []string {
|
||||
return f.Photos
|
||||
}
|
||||
|
||||
// String returns a string containing all selected item UIDs.
|
||||
func (f PhotosRequest) String() string {
|
||||
return strings.Join(f.Get(), ", ")
|
||||
}
|
||||
442
internal/form/batch/testdata/photos.json
vendored
Normal file
442
internal/form/batch/testdata/photos.json
vendored
Normal file
@@ -0,0 +1,442 @@
|
||||
[
|
||||
{
|
||||
"ID": "1000003-1000011",
|
||||
"UID": "ps6sg6be2lvl0yh0",
|
||||
"Type": "video",
|
||||
"TypeSrc": "",
|
||||
"TakenAt": "1990-04-18T01:00:00Z",
|
||||
"TakenAtLocal": "1990-04-18T01:00:00Z",
|
||||
"TakenSrc": "meta",
|
||||
"TimeZone": "Local",
|
||||
"Path": "",
|
||||
"Name": "",
|
||||
"Title": "",
|
||||
"Caption": "",
|
||||
"Year": 1990,
|
||||
"Month": 4,
|
||||
"Day": 18,
|
||||
"Country": "za",
|
||||
"Stack": 0,
|
||||
"Favorite": false,
|
||||
"Private": false,
|
||||
"Iso": 400,
|
||||
"FocalLength": 84,
|
||||
"FNumber": 4.5,
|
||||
"Exposure": "",
|
||||
"Faces": 1,
|
||||
"Quality": 4,
|
||||
"Resolution": 45,
|
||||
"Duration": 7200000000000,
|
||||
"Color": 12,
|
||||
"Scan": false,
|
||||
"Panorama": false,
|
||||
"CameraID": 1000003,
|
||||
"CameraMake": "Canon",
|
||||
"CameraModel": "EOS 6D",
|
||||
"LensID": 1000000,
|
||||
"LensMake": "Apple",
|
||||
"LensModel": "F380",
|
||||
"Altitude": -100,
|
||||
"Lat": 48.519234,
|
||||
"Lng": 9.057997,
|
||||
"CellID": "",
|
||||
"PlaceID": "",
|
||||
"PlaceSrc": "",
|
||||
"PlaceLabel": "",
|
||||
"PlaceCity": "",
|
||||
"PlaceState": "",
|
||||
"PlaceCountry": "",
|
||||
"InstanceID": "",
|
||||
"FileUID": "fs6sg6bw15bnlqdw",
|
||||
"FileRoot": "/",
|
||||
"FileName": "1990/04/bridge2.jpg",
|
||||
"OriginalName": "",
|
||||
"Hash": "pcad9168fa6acc5c5c2965adf6ec465ca42fd818",
|
||||
"Width": 1200,
|
||||
"Height": 1600,
|
||||
"Portrait": true,
|
||||
"Merged": true,
|
||||
"CreatedAt": "0001-01-01T00:00:00Z",
|
||||
"UpdatedAt": "0001-01-01T00:00:00Z",
|
||||
"EditedAt": "0001-01-01T00:00:00Z",
|
||||
"CheckedAt": "0001-01-01T00:00:00Z",
|
||||
"DetailsKeywords": "bridge, nature",
|
||||
"DetailsSubject": "Bridge",
|
||||
"DetailsArtist": "Jens Mander",
|
||||
"DetailsCopyright": "Copyright 2020",
|
||||
"DetailsLicense": "n/a",
|
||||
"Files": [
|
||||
{
|
||||
"UID": "fs6sg6bw15bnlqdw",
|
||||
"PhotoUID": "ps6sg6be2lvl0yh0",
|
||||
"Name": "1990/04/bridge2.jpg",
|
||||
"Root": "/",
|
||||
"Hash": "pcad9168fa6acc5c5c2965adf6ec465ca42fd818",
|
||||
"Size": 921858,
|
||||
"Primary": true,
|
||||
"Codec": "jpeg",
|
||||
"FileType": "jpg",
|
||||
"MediaType": "image",
|
||||
"Mime": "image/jpg",
|
||||
"Portrait": true,
|
||||
"Width": 1200,
|
||||
"Height": 1600,
|
||||
"Orientation": 6,
|
||||
"AspectRatio": 0.75,
|
||||
"CreatedAt": "0001-01-01T00:00:00Z",
|
||||
"UpdatedAt": "0001-01-01T00:00:00Z",
|
||||
"Markers": [
|
||||
{
|
||||
"UID": "ms6sg6b1wowuy777",
|
||||
"FileUID": "fs6sg6bw15bnlqdw",
|
||||
"Type": "face",
|
||||
"Src": "image",
|
||||
"Name": "",
|
||||
"Review": false,
|
||||
"Invalid": false,
|
||||
"FaceID": "TOSCDXCS4VI3PGIUTCNIQCNI6HSFXQVZ",
|
||||
"FaceDist": 0.6,
|
||||
"SubjUID": "",
|
||||
"SubjSrc": "",
|
||||
"X": 0.404687,
|
||||
"Y": 0.249707,
|
||||
"W": 0.214062,
|
||||
"H": 0.321219,
|
||||
"Size": 200,
|
||||
"Score": 74,
|
||||
"Thumb": "pcad9168fa6acc5c5c2965ddf6ec465ca42fd818",
|
||||
"CreatedAt": "2025-05-04T11:49:42.529705909Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"UID": "fs6sg6bwhhbnlqdn",
|
||||
"PhotoUID": "ps6sg6be2lvl0yh0",
|
||||
"Name": "London/bridge3.jpg",
|
||||
"Root": "/",
|
||||
"Hash": "pcad9168fa6acc5c5ba965adf6ec465ca42fd818",
|
||||
"Size": 921851,
|
||||
"Primary": false,
|
||||
"Codec": "jpeg",
|
||||
"FileType": "jpg",
|
||||
"MediaType": "image",
|
||||
"Mime": "image/jpg",
|
||||
"Portrait": true,
|
||||
"Width": 1200,
|
||||
"Height": 1600,
|
||||
"Orientation": 6,
|
||||
"AspectRatio": 0.75,
|
||||
"CreatedAt": "0001-01-01T00:00:00Z",
|
||||
"UpdatedAt": "0001-01-01T00:00:00Z",
|
||||
"Markers": [
|
||||
{
|
||||
"UID": "ms6sg6b1wowu1000",
|
||||
"FileUID": "fs6sg6bwhhbnlqdn",
|
||||
"Type": "face",
|
||||
"Src": "image",
|
||||
"Name": "Actress A",
|
||||
"Review": false,
|
||||
"Invalid": false,
|
||||
"FaceID": "GMH5NISEEULNJL6RATITOA3TMZXMTMCI",
|
||||
"FaceDist": 0.4507357278575355,
|
||||
"SubjUID": "js6sg6b1h1njaaac",
|
||||
"SubjSrc": "",
|
||||
"X": 0.464844,
|
||||
"Y": 0.449531,
|
||||
"W": 0.434375,
|
||||
"H": 0.652582,
|
||||
"Size": 556,
|
||||
"Score": 155,
|
||||
"Thumb": "pcad9168fa6acc5c5c2965ddf6ec465ca42fd818-046045043065",
|
||||
"CreatedAt": "2025-05-04T11:49:42.442163583Z"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"UID": "fs6sg6bwhhbnlqdy",
|
||||
"PhotoUID": "ps6sg6be2lvl0yh0",
|
||||
"Name": "1990/04/bridge2.mp4",
|
||||
"Root": "/",
|
||||
"Hash": "pcad9168fa6acc5c5ba965adf6ec465ca42fd819",
|
||||
"Size": 921851,
|
||||
"Primary": false,
|
||||
"Codec": "avc1",
|
||||
"FileType": "mp4",
|
||||
"MediaType": "video",
|
||||
"Mime": "image/mp4",
|
||||
"Portrait": true,
|
||||
"Video": true,
|
||||
"Duration": 17000000000,
|
||||
"Width": 1200,
|
||||
"Height": 1600,
|
||||
"Orientation": 6,
|
||||
"AspectRatio": 0.75,
|
||||
"CreatedAt": "0001-01-01T00:00:00Z",
|
||||
"UpdatedAt": "0001-01-01T00:00:00Z",
|
||||
"Markers": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"ID": "1000001-1000001",
|
||||
"UID": "ps6sg6be2lvl0yh8",
|
||||
"Type": "raw",
|
||||
"TypeSrc": "",
|
||||
"TakenAt": "2006-01-01T02:00:00Z",
|
||||
"TakenAtLocal": "2006-01-01T02:00:00Z",
|
||||
"TakenSrc": "meta",
|
||||
"TimeZone": "Europe/Berlin",
|
||||
"Path": "",
|
||||
"Name": "",
|
||||
"Title": "",
|
||||
"Caption": "photo caption non-photographic",
|
||||
"Year": 2790,
|
||||
"Month": 2,
|
||||
"Day": 12,
|
||||
"Country": "de",
|
||||
"Stack": 0,
|
||||
"Favorite": true,
|
||||
"Private": false,
|
||||
"Iso": 305,
|
||||
"FocalLength": 28,
|
||||
"FNumber": 3.5,
|
||||
"Exposure": "",
|
||||
"Quality": 3,
|
||||
"Resolution": 2,
|
||||
"Color": 3,
|
||||
"Scan": false,
|
||||
"Panorama": false,
|
||||
"CameraID": 1000003,
|
||||
"CameraMake": "Canon",
|
||||
"CameraModel": "EOS 6D",
|
||||
"LensID": 1000000,
|
||||
"LensMake": "Apple",
|
||||
"LensModel": "F380",
|
||||
"Altitude": -10,
|
||||
"Lat": 48.519234,
|
||||
"Lng": 9.057997,
|
||||
"CellID": "",
|
||||
"PlaceID": "",
|
||||
"PlaceSrc": "",
|
||||
"PlaceLabel": "",
|
||||
"PlaceCity": "",
|
||||
"PlaceState": "",
|
||||
"PlaceCountry": "",
|
||||
"InstanceID": "",
|
||||
"FileUID": "fs6sg6bw45bn0001",
|
||||
"FileRoot": "/",
|
||||
"FileName": "2790/02/Photo01.dng",
|
||||
"OriginalName": "",
|
||||
"Hash": "3cad9168fa6acc5c5c2965ddf6ec465ca42fd818",
|
||||
"Width": 1200,
|
||||
"Height": 1600,
|
||||
"Portrait": true,
|
||||
"Merged": false,
|
||||
"CreatedAt": "0001-01-01T00:00:00Z",
|
||||
"UpdatedAt": "0001-01-01T00:00:00Z",
|
||||
"EditedAt": "0001-01-01T00:00:00Z",
|
||||
"CheckedAt": "0001-01-01T00:00:00Z",
|
||||
"DetailsKeywords": "screenshot, info",
|
||||
"DetailsSubject": "Non Photographic",
|
||||
"DetailsArtist": "Hans",
|
||||
"DetailsCopyright": "copy",
|
||||
"DetailsLicense": "MIT",
|
||||
"Files": [
|
||||
{
|
||||
"UID": "fs6sg6bw45bn0001",
|
||||
"PhotoUID": "ps6sg6be2lvl0yh8",
|
||||
"Name": "2790/02/Photo01.dng",
|
||||
"Root": "/",
|
||||
"Hash": "3cad9168fa6acc5c5c2965ddf6ec465ca42fd818",
|
||||
"Size": 661858,
|
||||
"Primary": false,
|
||||
"Codec": "jpeg",
|
||||
"FileType": "raw",
|
||||
"MediaType": "raw",
|
||||
"Mime": "image/DNG",
|
||||
"Portrait": true,
|
||||
"Width": 1200,
|
||||
"Height": 1600,
|
||||
"Orientation": 6,
|
||||
"AspectRatio": 0.75,
|
||||
"CreatedAt": "0001-01-01T00:00:00Z",
|
||||
"UpdatedAt": "0001-01-01T00:00:00Z",
|
||||
"Markers": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"ID": "1000000-1000000",
|
||||
"UID": "ps6sg6be2lvl0yh7",
|
||||
"Type": "image",
|
||||
"TypeSrc": "",
|
||||
"TakenAt": "2008-07-01T10:00:00Z",
|
||||
"TakenAtLocal": "2008-07-01T12:00:00Z",
|
||||
"TakenSrc": "meta",
|
||||
"TimeZone": "Europe/Berlin",
|
||||
"Path": "",
|
||||
"Name": "",
|
||||
"Title": "Lake / 2790",
|
||||
"Caption": "photo caption lake",
|
||||
"Year": 2790,
|
||||
"Month": 7,
|
||||
"Day": 4,
|
||||
"Country": "zz",
|
||||
"Stack": 0,
|
||||
"Favorite": false,
|
||||
"Private": false,
|
||||
"Iso": 200,
|
||||
"FocalLength": 50,
|
||||
"FNumber": 5,
|
||||
"Exposure": "1/80",
|
||||
"Faces": 3,
|
||||
"Quality": 3,
|
||||
"Resolution": 2,
|
||||
"Color": 9,
|
||||
"Scan": false,
|
||||
"Panorama": false,
|
||||
"CameraID": 1000003,
|
||||
"CameraSrc": "meta",
|
||||
"CameraMake": "Canon",
|
||||
"CameraModel": "EOS 6D",
|
||||
"LensID": 1000000,
|
||||
"LensMake": "Apple",
|
||||
"LensModel": "F380",
|
||||
"Lat": 0,
|
||||
"Lng": 0,
|
||||
"CellID": "",
|
||||
"PlaceID": "",
|
||||
"PlaceSrc": "",
|
||||
"PlaceLabel": "",
|
||||
"PlaceCity": "",
|
||||
"PlaceState": "",
|
||||
"PlaceCountry": "",
|
||||
"InstanceID": "",
|
||||
"FileUID": "fs6sg6bw45bnlqdw",
|
||||
"FileRoot": "/",
|
||||
"FileName": "2790/07/27900704_070228_D6D51B6C.jpg",
|
||||
"OriginalName": "Vacation/exampleFileNameOriginal.jpg",
|
||||
"Hash": "2cad9168fa6acc5c5c2965ddf6ec465ca42fd818",
|
||||
"Width": 3648,
|
||||
"Height": 2736,
|
||||
"Portrait": false,
|
||||
"Merged": false,
|
||||
"CreatedAt": "0001-01-01T00:00:00Z",
|
||||
"UpdatedAt": "0001-01-01T00:00:00Z",
|
||||
"EditedAt": "0001-01-01T00:00:00Z",
|
||||
"CheckedAt": "0001-01-01T00:00:00Z",
|
||||
"DetailsKeywords": "nature, frog",
|
||||
"DetailsSubject": "Lake",
|
||||
"DetailsArtist": "Hans",
|
||||
"DetailsCopyright": "copy",
|
||||
"DetailsLicense": "MIT",
|
||||
"Files": [
|
||||
{
|
||||
"UID": "fs6sg6bw45bnlqdw",
|
||||
"PhotoUID": "ps6sg6be2lvl0yh7",
|
||||
"Name": "2790/07/27900704_070228_D6D51B6C.jpg",
|
||||
"Root": "/",
|
||||
"Hash": "2cad9168fa6acc5c5c2965ddf6ec465ca42fd818",
|
||||
"Size": 4278906,
|
||||
"Primary": true,
|
||||
"OriginalName": "Vacation/exampleFileNameOriginal.jpg",
|
||||
"Codec": "jpeg",
|
||||
"FileType": "jpg",
|
||||
"MediaType": "image",
|
||||
"Mime": "image/jpg",
|
||||
"Width": 3648,
|
||||
"Height": 2736,
|
||||
"Projection": "equirectangular",
|
||||
"AspectRatio": 1.33333,
|
||||
"CreatedAt": "0001-01-01T00:00:00Z",
|
||||
"UpdatedAt": "0001-01-01T00:00:00Z",
|
||||
"Markers": [
|
||||
{
|
||||
"UID": "ms6sg6b14ahkyd24",
|
||||
"FileUID": "fs6sg6bw45bnlqdw",
|
||||
"Type": "face",
|
||||
"Src": "image",
|
||||
"Name": "",
|
||||
"Review": false,
|
||||
"Invalid": false,
|
||||
"FaceID": "VF7ANLDET2BKZNT4VQWJMMC6HBEFDOG6",
|
||||
"FaceDist": 0.3139983399779298,
|
||||
"SubjUID": "",
|
||||
"SubjSrc": "",
|
||||
"X": 0.1,
|
||||
"Y": 0.229688,
|
||||
"W": 0.246334,
|
||||
"H": 0.29707,
|
||||
"Size": 209,
|
||||
"Score": 55,
|
||||
"Thumb": "acad9168fa6acc5c5c2965ddf6ec465ca42fd818",
|
||||
"CreatedAt": "2025-05-04T11:49:42.485807442Z"
|
||||
},
|
||||
{
|
||||
"UID": "ms6sg6b1wowu1005",
|
||||
"FileUID": "fs6sg6bw45bnlqdw",
|
||||
"Type": "face",
|
||||
"Src": "image",
|
||||
"Name": "Actor A",
|
||||
"Review": false,
|
||||
"Invalid": false,
|
||||
"FaceID": "PI6A2XGOTUXEFI7CBF4KCI5I2I3JEJHS",
|
||||
"FaceDist": 0.3139983399779298,
|
||||
"SubjUID": "js6sg6b1h1njaaad",
|
||||
"SubjSrc": "",
|
||||
"X": 0.5,
|
||||
"Y": 0.429688,
|
||||
"W": 0.746334,
|
||||
"H": 0.49707,
|
||||
"Size": 509,
|
||||
"Score": 100,
|
||||
"Thumb": "pcad9168fa6acc5c5c2965ddf6ec465ca42fd818",
|
||||
"CreatedAt": "2025-05-04T11:49:42.626934696Z"
|
||||
},
|
||||
{
|
||||
"UID": "ms6sg6b1wowuy888",
|
||||
"FileUID": "fs6sg6bw45bnlqdw",
|
||||
"Type": "face",
|
||||
"Src": "image",
|
||||
"Name": "",
|
||||
"Review": false,
|
||||
"Invalid": false,
|
||||
"FaceID": "TOSCDXCS4VI3PGIUTCNIQCNI6HSFXQVZ",
|
||||
"FaceDist": 0.6,
|
||||
"SubjUID": "",
|
||||
"SubjSrc": "",
|
||||
"X": 0.528125,
|
||||
"Y": 0.240328,
|
||||
"W": 0.3625,
|
||||
"H": 0.543962,
|
||||
"Size": 200,
|
||||
"Score": 56,
|
||||
"Thumb": "pcad9168fa6acc5c5c2965ddf6ec465ca42fd818",
|
||||
"CreatedAt": "2025-05-04T11:49:42.427572061Z"
|
||||
},
|
||||
{
|
||||
"UID": "ms6sg6b1wowu1001",
|
||||
"FileUID": "fs6sg6bw45bnlqdw",
|
||||
"Type": "face",
|
||||
"Src": "image",
|
||||
"Name": "Actress A",
|
||||
"Review": false,
|
||||
"Invalid": false,
|
||||
"FaceID": "GMH5NISEEULNJL6RATITOA3TMZXMTMCI",
|
||||
"FaceDist": 0.5099754448545762,
|
||||
"SubjUID": "js6sg6b1h1njaaac",
|
||||
"SubjSrc": "",
|
||||
"X": 0.547656,
|
||||
"Y": 0.330986,
|
||||
"W": 0.402344,
|
||||
"H": 0.60446,
|
||||
"Size": 515,
|
||||
"Score": 102,
|
||||
"Thumb": "pcad9168fa6acc5c5c2965ddf6ec465ca42fd818-05403304060446",
|
||||
"CreatedAt": "2025-05-04T11:49:42.457213555Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -6,49 +6,49 @@ import (
|
||||
|
||||
// String represents batch edit form value.
|
||||
type String struct {
|
||||
Value string `json:"value"`
|
||||
Matches bool `json:"matches"`
|
||||
Action Action `json:"action"`
|
||||
Value string `json:"value"`
|
||||
Mixed bool `json:"mixed"`
|
||||
Action Action `json:"action"`
|
||||
}
|
||||
|
||||
// Bool represents batch edit form value.
|
||||
type Bool struct {
|
||||
Value bool `json:"value"`
|
||||
Matches bool `json:"matches"`
|
||||
Action Action `json:"action"`
|
||||
Value bool `json:"value"`
|
||||
Mixed bool `json:"mixed"`
|
||||
Action Action `json:"action"`
|
||||
}
|
||||
|
||||
// Time represents batch edit form value.
|
||||
type Time struct {
|
||||
Value time.Time `json:"value"`
|
||||
Matches bool `json:"matches"`
|
||||
Action Action `json:"action"`
|
||||
Value time.Time `json:"value"`
|
||||
Mixed bool `json:"mixed"`
|
||||
Action Action `json:"action"`
|
||||
}
|
||||
|
||||
// Int represents batch edit form value.
|
||||
type Int struct {
|
||||
Value int `json:"value"`
|
||||
Matches bool `json:"matches"`
|
||||
Action Action `json:"action"`
|
||||
Value int `json:"value"`
|
||||
Mixed bool `json:"mixed"`
|
||||
Action Action `json:"action"`
|
||||
}
|
||||
|
||||
// UInt represents batch edit form value.
|
||||
type UInt struct {
|
||||
Value uint `json:"value"`
|
||||
Matches bool `json:"matches"`
|
||||
Action Action `json:"action"`
|
||||
Value uint `json:"value"`
|
||||
Mixed bool `json:"mixed"`
|
||||
Action Action `json:"action"`
|
||||
}
|
||||
|
||||
// Float32 represents batch edit form value.
|
||||
type Float32 struct {
|
||||
Value float32 `json:"value"`
|
||||
Matches bool `json:"matches"`
|
||||
Action Action `json:"action"`
|
||||
Value float32 `json:"value"`
|
||||
Mixed bool `json:"mixed"`
|
||||
Action Action `json:"action"`
|
||||
}
|
||||
|
||||
// Float64 represents batch edit form value.
|
||||
type Float64 struct {
|
||||
Value float64 `json:"value"`
|
||||
Matches bool `json:"matches"`
|
||||
Action Action `json:"action"`
|
||||
Value float64 `json:"value"`
|
||||
Mixed bool `json:"mixed"`
|
||||
Action Action `json:"action"`
|
||||
}
|
||||
|
||||
@@ -99,6 +99,7 @@ type SearchPhotos struct {
|
||||
Offset int `form:"offset" serialize:"-"` // Result FILE offset
|
||||
Order string `form:"order" serialize:"-"` // Sort order
|
||||
Merged bool `form:"merged" serialize:"-"` // Merge FILES in response
|
||||
Details bool `form:"-" serialize:"-"` // Include additional information from details table
|
||||
}
|
||||
|
||||
func (f *SearchPhotos) GetQuery() string {
|
||||
|
||||
@@ -5,6 +5,7 @@ import "strings"
|
||||
// Selection represents items selected in the user interface.
|
||||
type Selection struct {
|
||||
All bool `json:"all"`
|
||||
Filter string `json:"filter"`
|
||||
Files []string `json:"files"`
|
||||
Photos []string `json:"photos"`
|
||||
Albums []string `json:"albums"`
|
||||
|
||||
Reference in New Issue
Block a user