Panoramas: Increase projection type string limit to 32 characters #1508
This commit is contained in:
parent
34c8f9d7b1
commit
2bde7e5696
7 changed files with 178 additions and 49 deletions
|
@ -1,7 +1,69 @@
|
|||
package entity
|
||||
|
||||
// Panorama Projection Types
|
||||
// TODO: Move to separate package.
|
||||
|
||||
const (
|
||||
ProjDefault = ""
|
||||
ProjEquirectangular = "equirectangular"
|
||||
ProjCubestrip = "cubestrip"
|
||||
ProjCylindrical = "cylindrical"
|
||||
ProjTransverseCylindrical = "transverse-cylindrical"
|
||||
ProjPseudocylindricalCompromise = "pseudocylindrical-compromise"
|
||||
)
|
||||
|
||||
// Content Types
|
||||
|
||||
const (
|
||||
TypeDefault = ""
|
||||
TypeImage = "image"
|
||||
TypeLive = "live"
|
||||
TypeVideo = "video"
|
||||
TypeRaw = "raw"
|
||||
TypeText = "text"
|
||||
)
|
||||
|
||||
// Root Directories Types
|
||||
|
||||
const (
|
||||
RootUnknown = ""
|
||||
RootOriginals = "/"
|
||||
RootExamples = "examples"
|
||||
RootSidecar = "sidecar"
|
||||
RootImport = "import"
|
||||
RootPath = "/"
|
||||
)
|
||||
|
||||
// Unknown Values
|
||||
|
||||
const (
|
||||
UnknownYear = -1
|
||||
UnknownMonth = -1
|
||||
UnknownDay = -1
|
||||
UnknownName = "Unknown"
|
||||
UnknownTitle = UnknownName
|
||||
UnknownID = "zz"
|
||||
)
|
||||
|
||||
// Event Types
|
||||
|
||||
const (
|
||||
Updated = "updated"
|
||||
Created = "created"
|
||||
Deleted = "deleted"
|
||||
)
|
||||
|
||||
// Photo Stacks
|
||||
|
||||
const (
|
||||
IsStacked int8 = 1
|
||||
IsStackable int8 = 0
|
||||
IsUnstacked int8 = -1
|
||||
)
|
||||
|
||||
// Sort Orders
|
||||
|
||||
const (
|
||||
// Sort orders:
|
||||
SortOrderAdded = "added"
|
||||
SortOrderNewest = "newest"
|
||||
SortOrderOldest = "oldest"
|
||||
|
@ -9,44 +71,4 @@ const (
|
|||
SortOrderSimilar = "similar"
|
||||
SortOrderRelevance = "relevance"
|
||||
SortOrderEdited = "edited"
|
||||
|
||||
// Unknown values:
|
||||
UnknownYear = -1
|
||||
UnknownMonth = -1
|
||||
UnknownDay = -1
|
||||
UnknownName = "Unknown"
|
||||
UnknownTitle = UnknownName
|
||||
UnknownID = "zz"
|
||||
|
||||
// Content types:
|
||||
TypeDefault = ""
|
||||
TypeImage = "image"
|
||||
TypeLive = "live"
|
||||
TypeVideo = "video"
|
||||
TypeRaw = "raw"
|
||||
TypeText = "text"
|
||||
|
||||
// Root directories:
|
||||
RootUnknown = ""
|
||||
RootOriginals = "/"
|
||||
RootExamples = "examples"
|
||||
RootSidecar = "sidecar"
|
||||
RootImport = "import"
|
||||
RootPath = "/"
|
||||
|
||||
// Panorama projections:
|
||||
ProjectionDefault = ""
|
||||
ProjectionEquirectangular = "equirectangular"
|
||||
ProjectionCubestrip = "cubestrip"
|
||||
ProjectionCylindrical = "cylindrical"
|
||||
|
||||
// Event names:
|
||||
Updated = "updated"
|
||||
Created = "created"
|
||||
Deleted = "deleted"
|
||||
|
||||
// Photo stacks:
|
||||
IsStacked int8 = 1
|
||||
IsStackable int8 = 0
|
||||
IsUnstacked int8 = -1
|
||||
)
|
||||
|
|
|
@ -53,7 +53,7 @@ type File struct {
|
|||
FileWidth int `json:"Width" yaml:"Width,omitempty"`
|
||||
FileHeight int `json:"Height" yaml:"Height,omitempty"`
|
||||
FileOrientation int `json:"Orientation" yaml:"Orientation,omitempty"`
|
||||
FileProjection string `gorm:"type:VARBINARY(16);" json:"Projection,omitempty" yaml:"Projection,omitempty"`
|
||||
FileProjection string `gorm:"type:VARBINARY(32);" json:"Projection,omitempty" yaml:"Projection,omitempty"`
|
||||
FileAspectRatio float32 `gorm:"type:FLOAT;" json:"AspectRatio" yaml:"AspectRatio,omitempty"`
|
||||
FileMainColor string `gorm:"type:VARBINARY(16);index;" json:"MainColor" yaml:"MainColor,omitempty"`
|
||||
FileColors string `gorm:"type:VARBINARY(9);" json:"Colors" yaml:"Colors,omitempty"`
|
||||
|
@ -394,7 +394,17 @@ func (m *File) Panorama() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
return m.FileProjection != ProjectionDefault || (m.FileWidth/m.FileHeight) >= 2
|
||||
return m.Projection() != ProjDefault || (m.FileWidth/m.FileHeight) >= 2
|
||||
}
|
||||
|
||||
// Projection returns the panorama projection type string.
|
||||
func (m *File) Projection() string {
|
||||
return SanitizeTypeString(m.FileProjection)
|
||||
}
|
||||
|
||||
// SetProjection sets the panorama projection type string.
|
||||
func (m *File) SetProjection(projType string) {
|
||||
m.FileProjection = SanitizeTypeString(projType)
|
||||
}
|
||||
|
||||
// AddFaces adds face markers to the file.
|
||||
|
|
|
@ -289,7 +289,11 @@ func TestFile_Panorama(t *testing.T) {
|
|||
assert.False(t, file.Panorama())
|
||||
})
|
||||
t.Run("equirectangular", func(t *testing.T) {
|
||||
file := &File{Photo: nil, FileType: "jpg", FileSidecar: false, FileWidth: 1500, FileHeight: 1000, FileProjection: ProjectionEquirectangular}
|
||||
file := &File{Photo: nil, FileType: "jpg", FileSidecar: false, FileWidth: 1500, FileHeight: 1000, FileProjection: ProjEquirectangular}
|
||||
assert.True(t, file.Panorama())
|
||||
})
|
||||
t.Run("transverse-cylindrical", func(t *testing.T) {
|
||||
file := &File{Photo: nil, FileType: "jpg", FileSidecar: false, FileWidth: 1500, FileHeight: 1000, FileProjection: ProjTransverseCylindrical}
|
||||
assert.True(t, file.Panorama())
|
||||
})
|
||||
t.Run("sidecar", func(t *testing.T) {
|
||||
|
@ -298,6 +302,39 @@ func TestFile_Panorama(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestFile_SetProjection(t *testing.T) {
|
||||
t.Run(ProjDefault, func(t *testing.T) {
|
||||
m := &File{}
|
||||
m.SetProjection(ProjDefault)
|
||||
assert.Equal(t, ProjDefault, m.FileProjection)
|
||||
})
|
||||
t.Run(ProjCubestrip, func(t *testing.T) {
|
||||
m := &File{}
|
||||
m.SetProjection(ProjCubestrip)
|
||||
assert.Equal(t, ProjCubestrip, m.FileProjection)
|
||||
})
|
||||
t.Run(ProjCylindrical, func(t *testing.T) {
|
||||
m := &File{}
|
||||
m.SetProjection(ProjCylindrical)
|
||||
assert.Equal(t, ProjCylindrical, m.FileProjection)
|
||||
})
|
||||
t.Run(ProjTransverseCylindrical, func(t *testing.T) {
|
||||
m := &File{}
|
||||
m.SetProjection(ProjTransverseCylindrical)
|
||||
assert.Equal(t, ProjTransverseCylindrical, m.FileProjection)
|
||||
})
|
||||
t.Run(ProjPseudocylindricalCompromise, func(t *testing.T) {
|
||||
m := &File{}
|
||||
m.SetProjection(ProjPseudocylindricalCompromise)
|
||||
assert.Equal(t, ProjPseudocylindricalCompromise, m.FileProjection)
|
||||
})
|
||||
t.Run("Sanitize", func(t *testing.T) {
|
||||
m := &File{}
|
||||
m.SetProjection(" 幸福 Hanzi are logograms developed for the writing of Chinese! ")
|
||||
assert.Equal(t, "hanzi are logograms developed for the writing of chinese", m.FileProjection)
|
||||
})
|
||||
}
|
||||
|
||||
func TestFile_Delete(t *testing.T) {
|
||||
t.Run("permanently", func(t *testing.T) {
|
||||
file := &File{FileType: "jpg", FileSize: 500, FileName: "ToBePermanentlyDeleted", FileRoot: "", PhotoID: 5678}
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
package entity
|
||||
|
||||
import "reflect"
|
||||
import (
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
TrimTypeString = 32
|
||||
)
|
||||
|
||||
// Values is a shortcut for map[string]interface{}
|
||||
type Values map[string]interface{}
|
||||
|
@ -34,3 +41,33 @@ func GetValues(m interface{}, omit ...string) (result Values) {
|
|||
|
||||
return result
|
||||
}
|
||||
|
||||
// ToASCII removes all non-ascii characters from a string and returns it.
|
||||
func ToASCII(s string) string {
|
||||
result := make([]rune, 0, len(s))
|
||||
|
||||
for _, r := range s {
|
||||
if r <= 127 {
|
||||
result = append(result, r)
|
||||
}
|
||||
}
|
||||
|
||||
return string(result)
|
||||
}
|
||||
|
||||
// Trim shortens a string to the given number of characters, and removes all leading and trailing white space.
|
||||
func Trim(s string, maxLen int) string {
|
||||
s = strings.TrimSpace(s)
|
||||
l := len(s)
|
||||
|
||||
if l <= maxLen {
|
||||
return s
|
||||
} else {
|
||||
return s[:l-1]
|
||||
}
|
||||
}
|
||||
|
||||
// SanitizeTypeString converts a type string to lowercase, omits invalid runes, and shortens it if needed.
|
||||
func SanitizeTypeString(s string) string {
|
||||
return Trim(ToASCII(strings.ToLower(s)), TrimTypeString)
|
||||
}
|
||||
|
|
22
internal/entity/values_test.go
Normal file
22
internal/entity/values_test.go
Normal file
|
@ -0,0 +1,22 @@
|
|||
package entity
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestToASCII(t *testing.T) {
|
||||
result := ToASCII("幸福 = Happiness.")
|
||||
assert.Equal(t, " = Happiness.", result)
|
||||
}
|
||||
|
||||
func TestTrim(t *testing.T) {
|
||||
result := Trim(" 幸福 Hanzi are logograms developed for the writing of Chinese! ", 16)
|
||||
assert.Equal(t, "幸福 Hanzi are logograms developed for the writing of Chinese", result)
|
||||
}
|
||||
|
||||
func TestSanitizeTypeString(t *testing.T) {
|
||||
result := SanitizeTypeString(" 幸福 Hanzi are logograms developed for the writing of Chinese! ")
|
||||
assert.Equal(t, "hanzi are logograms developed for the writing of chinese", result)
|
||||
}
|
|
@ -321,7 +321,7 @@ func (ind *Index) MediaFile(m *MediaFile, o IndexOptions, originalName string) (
|
|||
|
||||
if metaData := m.MetaData(); metaData.Error == nil {
|
||||
file.FileCodec = metaData.Codec
|
||||
file.FileProjection = metaData.Projection
|
||||
file.SetProjection(metaData.Projection)
|
||||
|
||||
if metaData.HasInstanceID() {
|
||||
log.Infof("index: %s has instance_id %s", logName, txt.Quote(metaData.InstanceID))
|
||||
|
@ -379,7 +379,7 @@ func (ind *Index) MediaFile(m *MediaFile, o IndexOptions, originalName string) (
|
|||
file.FileHeight = m.Height()
|
||||
file.FileAspectRatio = m.AspectRatio()
|
||||
file.FilePortrait = m.Portrait()
|
||||
file.FileProjection = metaData.Projection
|
||||
file.SetProjection(metaData.Projection)
|
||||
|
||||
if res := m.Megapixels(); res > photo.PhotoResolution {
|
||||
photo.PhotoResolution = res
|
||||
|
@ -429,7 +429,7 @@ func (ind *Index) MediaFile(m *MediaFile, o IndexOptions, originalName string) (
|
|||
file.FileAspectRatio = m.AspectRatio()
|
||||
file.FilePortrait = m.Portrait()
|
||||
file.FileDuration = metaData.Duration
|
||||
file.FileProjection = metaData.Projection
|
||||
file.SetProjection(metaData.Projection)
|
||||
|
||||
if res := m.Megapixels(); res > photo.PhotoResolution {
|
||||
photo.PhotoResolution = res
|
||||
|
|
|
@ -4,13 +4,14 @@ import "strings"
|
|||
|
||||
const (
|
||||
ClipDefault = 160
|
||||
ClipSlug = 80
|
||||
ClipKeyword = 40
|
||||
ClipSlug = 80
|
||||
ClipVarchar = 255
|
||||
ClipQuery = 1000
|
||||
ClipDescription = 16000
|
||||
)
|
||||
|
||||
// Clip shortens a string to the given number of runes, and removes all leading and trailing white space.
|
||||
func Clip(s string, size int) string {
|
||||
s = strings.TrimSpace(s)
|
||||
|
||||
|
|
Loading…
Reference in a new issue