Merge remote-tracking branch 'origin/develop' into develop

This commit is contained in:
Theresa Gresch 2020-04-26 16:35:40 +02:00
commit 65f47a5db4
6 changed files with 108 additions and 54 deletions

View File

@ -84,19 +84,29 @@
</h3>
<div class="caption">
<button @click.exact="editPhoto(index)">
<v-icon size="14">date_range</v-icon>
<v-icon size="14" title="Taken" v-if="photo.TakenSrc">date_range</v-icon>
<v-icon size="14" title="Imported" v-else>save</v-icon>
{{ photo.getDateString() }}
</button>
<br/>
<button @click.exact="editPhoto(index)">
<button @click.exact="editPhoto(index)" title="Camera">
<v-icon size="14">photo_camera</v-icon>
{{ photo.getCamera() }}
</button>
<br/>
<button @click.exact="openLocation(index)" v-if="showLocation && photo.LocationID">
<v-icon size="14">location_on</v-icon>
{{ photo.getLocation() }}
</button>
<template v-if="showLocation && photo.LocationID">
<br/>
<button @click.exact="openLocation(index)" title="Location">
<v-icon size="14">location_on</v-icon>
{{ photo.getLocation() }}
</button>
</template>
<template v-if="debug">
<br/>
<button @click.exact="openUUID(index)" title="Unique ID">
<v-icon size="14">fingerprint</v-icon>
{{ photo.PhotoUUID }}
</button>
</template>
</div>
</div>
</v-card-title>
@ -121,6 +131,7 @@
return {
showLocation: this.$config.settings().features.places,
hidePrivate: this.$config.settings().library.private,
debug: this.$config.get('debug'),
mouseDown: {
index: -1,
timeStamp: -1,
@ -161,7 +172,10 @@
},
selectRange(index) {
this.$clipboard.addRange(index, this.photos);
}
},
openUUID(index) {
window.open("/api/v1/" + this.photos[index].getEntityResource(), '_blank');
},
}
};
</script>

View File

@ -33,7 +33,7 @@ func GetPhoto(router *gin.RouterGroup, conf *config.Config) {
return
}
c.JSON(http.StatusOK, p)
c.IndentedJSON(http.StatusOK, p)
})
}

View File

@ -18,13 +18,14 @@ import (
// Photo represents a photo, all its properties, and link to all its images and sidecar files.
type Photo struct {
ID uint `gorm:"primary_key"`
TakenAt time.Time `gorm:"type:datetime;index:idx_photos_taken_uuid;" json:"TakenAt"`
TakenSrc string `gorm:"type:varbinary(8);" json:"TakenSrc"`
PhotoUUID string `gorm:"type:varbinary(36);unique_index;index:idx_photos_taken_uuid;"`
PhotoPath string `gorm:"type:varbinary(768);index;"`
PhotoName string `gorm:"type:varbinary(255);"`
TakenAt time.Time `gorm:"type:datetime;index:idx_photos_taken_uuid;" json:"TakenAt"`
TakenAtLocal time.Time `gorm:"type:datetime;"`
TakenSrc string `gorm:"type:varbinary(8);" json:"TakenSrc"`
PhotoTitle string `gorm:"type:varchar(255);" json:"PhotoTitle"`
TitleSrc string `gorm:"type:varbinary(8);" json:"TitleSrc"`
PhotoPath string `gorm:"type:varbinary(768);index;"`
PhotoName string `gorm:"type:varbinary(255);"`
PhotoQuality int `gorm:"type:SMALLINT" json:"PhotoQuality"`
PhotoResolution int `gorm:"type:SMALLINT" json:"PhotoResolution"`
PhotoFavorite bool `json:"PhotoFavorite"`
@ -44,11 +45,10 @@ type Photo struct {
PlaceID string `gorm:"type:varbinary(16);index;default:'zz'" json:"PlaceID"`
LocationID string `gorm:"type:varbinary(16);index;" json:"LocationID"`
LocationSrc string `gorm:"type:varbinary(8);" json:"LocationSrc"`
TimeZone string `gorm:"type:varbinary(64);" json:"TimeZone"`
PhotoCountry string `gorm:"type:varbinary(2);index:idx_photos_country_year_month;default:'zz'" json:"PhotoCountry"`
PhotoYear int `gorm:"index:idx_photos_country_year_month;"`
PhotoMonth int `gorm:"index:idx_photos_country_year_month;"`
TimeZone string `gorm:"type:varbinary(64);" json:"TimeZone"`
TakenAtLocal time.Time `gorm:"type:datetime;"`
Description Description `json:"Description"`
DescriptionSrc string `gorm:"type:varbinary(8);" json:"DescriptionSrc"`
Camera *Camera `json:"Camera"`
@ -402,7 +402,7 @@ func (m *Photo) AddLabels(labels classify.Labels, db *gorm.DB) {
db.Set("gorm:auto_preload", true).Model(m).Related(&m.Labels)
}
// SetTitle sets the photo title and clips it to 300 characters.
// SetTitle changes the photo title and clips it to 300 characters.
func (m *Photo) SetTitle(title, source string) {
newTitle := txt.Clip(title, txt.ClipDefault)
@ -410,6 +410,68 @@ func (m *Photo) SetTitle(title, source string) {
return
}
if m.TitleSrc != SrcAuto && m.TitleSrc != source && source != SrcManual && m.HasTitle() {
return
}
m.PhotoTitle = newTitle
m.TitleSrc = source
}
// SetDescription changes the photo description if not empty and from the same source.
func (m *Photo) SetDescription(desc, source string) {
newDesc := txt.Clip(desc, txt.ClipDescription)
if newDesc == "" {
return
}
if m.DescriptionSrc != SrcAuto && m.DescriptionSrc != source && source != SrcManual && m.Description.PhotoDescription != "" {
return
}
m.Description.PhotoDescription = newDesc
m.DescriptionSrc = source
}
// SetTakenAt changes the photo date if not empty and from the same source.
func (m *Photo) SetTakenAt(taken, local time.Time, zone, source string) {
if taken.IsZero() || taken.Year() < 1000 {
return
}
if m.TakenSrc != SrcAuto && m.TakenSrc != source && source != SrcManual {
return
}
m.TakenAt = taken.Round(time.Second).UTC()
m.TakenSrc = source
if local.IsZero() || local.Year() < 1000 {
m.TakenAtLocal = m.TakenAt
} else {
m.TakenAtLocal = local.Round(time.Second)
}
if zone != "" {
m.TimeZone = zone
} else {
m.TimeZone = time.UTC.String()
}
}
// SetCoordinates changes the photo lat, lng and altitude if not empty and from the same source.
func (m *Photo) SetCoordinates(lat, lng float32, altitude int, source string) {
if lat == 0 && lng == 0 {
return
}
if m.LocationSrc != SrcAuto && m.LocationSrc != source && source != SrcManual {
return
}
m.PhotoLat = lat
m.PhotoLng = lng
m.PhotoAltitude = altitude
m.LocationSrc = source
}

View File

@ -153,28 +153,10 @@ func (ind *Index) MediaFile(m *MediaFile, o IndexOptions, originalName string) (
if fileChanged || o.UpdateExif {
// Read UpdateExif data
if metaData, err := m.MetaData(); err == nil {
if photo.LocationSrc == entity.SrcAuto || photo.LocationSrc == entity.SrcExif {
photo.PhotoLat = metaData.Lat
photo.PhotoLng = metaData.Lng
photo.PhotoAltitude = metaData.Altitude
photo.LocationSrc = entity.SrcExif
}
if photo.TakenSrc == entity.SrcAuto || photo.TakenSrc == entity.SrcExif {
photo.TakenAt = metaData.TakenAt
photo.TakenAtLocal = metaData.TakenAtLocal
photo.TimeZone = metaData.TimeZone
photo.TakenSrc = entity.SrcExif
}
if metaData.Title != "" && (photo.NoTitle() || photo.TitleSrc == entity.SrcExif) {
photo.SetTitle(metaData.Title, entity.SrcExif)
}
if metaData.Description != "" && (photo.Description.NoDescription() || photo.DescriptionSrc == entity.SrcExif) {
photo.Description.PhotoDescription = metaData.Description
photo.DescriptionSrc = entity.SrcExif
}
photo.SetTitle(metaData.Title, entity.SrcExif)
photo.SetDescription(metaData.Description, entity.SrcExif)
photo.SetTakenAt(metaData.TakenAt, metaData.TakenAtLocal, metaData.TimeZone, entity.SrcExif)
photo.SetCoordinates(metaData.Lat, metaData.Lng, metaData.Altitude, entity.SrcExif)
if photo.Description.NoNotes() {
photo.Description.PhotoNotes = metaData.Comment
@ -219,8 +201,7 @@ func (ind *Index) MediaFile(m *MediaFile, o IndexOptions, originalName string) (
}
if photo.TakenAt.IsZero() || photo.TakenAtLocal.IsZero() {
photo.TakenAt = m.DateCreated()
photo.TakenAtLocal = photo.TakenAt
photo.SetTakenAt(m.DateCreated(), m.DateCreated(), time.UTC.String(), entity.SrcAuto)
}
if fileChanged || o.UpdateKeywords || o.UpdateLocation || o.UpdateTitle || photo.NoTitle() {
@ -238,24 +219,19 @@ func (ind *Index) MediaFile(m *MediaFile, o IndexOptions, originalName string) (
} else if m.IsXMP() {
// TODO: Proof-of-concept for indexing XMP sidecar files
if data, err := meta.XMP(m.FileName()); err == nil {
if data.Title != "" && photo.TitleSrc == entity.SrcAuto {
photo.SetTitle(data.Title, entity.SrcXmp)
}
photo.SetTitle(data.Title, entity.SrcXmp)
photo.SetDescription(data.Description, entity.SrcXmp)
if photo.Description.NoCopyright() && data.Copyright != "" {
photo.Description.PhotoCopyright = data.Copyright
if photo.Description.NoNotes() && data.Comment != "" {
photo.Description.PhotoNotes = data.Comment
}
if photo.Description.NoArtist() && data.Artist != "" {
photo.Description.PhotoArtist = data.Artist
}
if photo.Description.NoDescription() && data.Description != "" {
photo.Description.PhotoDescription = data.Description
}
if photo.Description.NoNotes() && data.Comment != "" {
photo.Description.PhotoNotes = data.Comment
if photo.Description.NoCopyright() && data.Copyright != "" {
photo.Description.PhotoCopyright = data.Copyright
}
}
}

View File

@ -24,6 +24,7 @@ type PhotoResult struct {
DeletedAt time.Time
TakenAt time.Time
TakenAtLocal time.Time
TakenSrc string
TimeZone string
PhotoUUID string
PhotoPath string

View File

@ -3,9 +3,10 @@ package txt
import "strings"
const (
ClipDefault = 160
ClipSlug = 80
ClipKeyword = 40
ClipDefault = 160
ClipSlug = 80
ClipKeyword = 40
ClipDescription = 16000
)
func Clip(s string, size int) string {