Backend: Move reusable packages to pkg/

Signed-off-by: Michael Mayer <michael@liquidbytes.net>
This commit is contained in:
Michael Mayer 2020-01-12 14:00:56 +01:00
parent fbea88bd74
commit f8a45b14d9
85 changed files with 5244 additions and 5239 deletions

View file

@ -83,23 +83,23 @@ acceptance-firefox:
(cd frontend && npm run acceptance-firefox)
test-go:
$(info Running all Go unit tests...)
$(GOTEST) -count=1 -tags=slow -timeout 20m ./internal/...
$(GOTEST) -count=1 -tags=slow -timeout 20m ./pkg/... ./internal/...
test-verbose:
$(info Running all Go unit tests in verbose mode...)
$(GOTEST) -tags=slow -timeout 20m -v ./internal/...
$(GOTEST) -tags=slow -timeout 20m -v ./pkg/... ./internal/...
test-short:
$(info Running short Go unit tests in verbose mode...)
$(GOTEST) -short -timeout 5m -v ./internal/...
$(GOTEST) -short -timeout 5m -v ./pkg/... ./internal/...
test-race:
$(info Running all Go unit tests with race detection in verbose mode...)
$(GOTEST) -tags=slow -race -timeout 60m -v ./internal/...
$(GOTEST) -tags=slow -race -timeout 60m -v ./pkg/... ./internal/...
test-codecov:
$(info Running all Go unit tests with code coverage report for codecov...)
go test -count=1 -tags=slow -timeout 30m -coverprofile=coverage.txt -covermode=atomic -v ./internal/...
go test -count=1 -tags=slow -timeout 30m -coverprofile=coverage.txt -covermode=atomic -v ./pkg/... ./internal/...
scripts/codecov.sh
test-coverage:
$(info Running all Go unit tests with code coverage report...)
go test -count=1 -tags=slow -timeout 30m -coverprofile=coverage.txt -covermode=atomic -v ./internal/...
go test -count=1 -tags=slow -timeout 30m -coverprofile=coverage.txt -covermode=atomic -v ./pkg/... ./internal/...
go tool cover -html=coverage.txt -o coverage.html
clean:
rm -f $(BINARY_NAME)
@ -131,8 +131,8 @@ lint-js:
fmt-js:
(cd frontend && npm run fmt)
fmt-go:
goimports -w internal cmd
go fmt ./internal/... ./cmd/...
goimports -w pkg internal cmd
go fmt ./pkg/... ./internal/... ./cmd/...
tidy:
go mod tidy
upgrade-js:

View file

@ -12,16 +12,16 @@ import (
"github.com/photoprism/photoprism/internal/entity"
"github.com/photoprism/photoprism/internal/event"
"github.com/photoprism/photoprism/internal/file"
"github.com/photoprism/photoprism/pkg/fs"
"github.com/photoprism/photoprism/internal/form"
"github.com/photoprism/photoprism/internal/query"
"github.com/photoprism/photoprism/internal/rnd"
"github.com/photoprism/photoprism/pkg/rnd"
"github.com/photoprism/photoprism/internal/thumb"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/txt"
"github.com/photoprism/photoprism/pkg/txt"
)
// GET /api/v1/albums
@ -368,7 +368,7 @@ func DownloadAlbum(router *gin.RouterGroup, conf *config.Config) {
fileName := path.Join(conf.OriginalsPath(), f.FileName)
fileAlias := f.DownloadFileName()
if file.Exists(fileName) {
if fs.FileExists(fileName) {
if err := addFileToZip(zipWriter, fileName, fileAlias); err != nil {
log.Error(err)
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": txt.UcFirst("failed to create zip file")})
@ -387,7 +387,7 @@ func DownloadAlbum(router *gin.RouterGroup, conf *config.Config) {
zipWriter.Close()
newZipFile.Close()
if !file.Exists(zipFileName) {
if !fs.FileExists(zipFileName) {
log.Errorf("could not find zip file: %s", zipFileName)
c.Data(404, "image/svg+xml", photoIconSvg)
return
@ -433,7 +433,7 @@ func AlbumThumbnail(router *gin.RouterGroup, conf *config.Config) {
fileName := path.Join(conf.OriginalsPath(), f.FileName)
if !file.Exists(fileName) {
if !fs.FileExists(fileName) {
log.Errorf("could not find original for thumbnail: %s", fileName)
c.Data(http.StatusNotFound, "image/svg+xml", photoIconSvg)

View file

@ -10,7 +10,7 @@ import (
"github.com/photoprism/photoprism/internal/entity"
"github.com/photoprism/photoprism/internal/event"
"github.com/photoprism/photoprism/internal/form"
"github.com/photoprism/photoprism/internal/txt"
"github.com/photoprism/photoprism/pkg/txt"
"github.com/gin-gonic/gin"
)

View file

@ -5,7 +5,7 @@ import (
"path"
"github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/file"
"github.com/photoprism/photoprism/pkg/fs"
"github.com/photoprism/photoprism/internal/query"
"github.com/gin-gonic/gin"
@ -33,7 +33,7 @@ func GetDownload(router *gin.RouterGroup, conf *config.Config) {
fileName := path.Join(conf.OriginalsPath(), f.FileName)
if !file.Exists(fileName) {
if !fs.FileExists(fileName) {
log.Errorf("could not find original: %s", fileHash)
c.Data(404, "image/svg+xml", photoIconSvg)

View file

@ -3,7 +3,7 @@ package api
import (
"github.com/gin-gonic/gin"
"github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/txt"
"github.com/photoprism/photoprism/pkg/txt"
)
var (

View file

@ -11,7 +11,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/event"
"github.com/photoprism/photoprism/internal/file"
"github.com/photoprism/photoprism/pkg/fs"
"github.com/photoprism/photoprism/internal/photoprism"
)
@ -60,7 +60,7 @@ func StartImport(router *gin.RouterGroup, conf *config.Config) {
imp.Start(path)
if subPath != "" && path != conf.ImportPath() && file.IsEmpty(path) {
if subPath != "" && path != conf.ImportPath() && fs.IsEmpty(path) {
if err := os.Remove(path); err != nil {
log.Errorf("import: could not deleted empty directory \"%s\": %s", path, err)
} else {

View file

@ -13,7 +13,7 @@ import (
"github.com/photoprism/photoprism/internal/form"
"github.com/photoprism/photoprism/internal/nsfw"
"github.com/photoprism/photoprism/internal/photoprism"
"github.com/photoprism/photoprism/internal/txt"
"github.com/photoprism/photoprism/pkg/txt"
)
var ind *photoprism.Index

View file

@ -12,11 +12,11 @@ import (
"github.com/gin-gonic/gin/binding"
"github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/event"
"github.com/photoprism/photoprism/internal/file"
"github.com/photoprism/photoprism/pkg/fs"
"github.com/photoprism/photoprism/internal/form"
"github.com/photoprism/photoprism/internal/query"
"github.com/photoprism/photoprism/internal/thumb"
"github.com/photoprism/photoprism/internal/txt"
"github.com/photoprism/photoprism/pkg/txt"
)
// GET /api/v1/labels
@ -153,7 +153,7 @@ func LabelThumbnail(router *gin.RouterGroup, conf *config.Config) {
fileName := path.Join(conf.OriginalsPath(), f.FileName)
if !file.Exists(fileName) {
if !fs.FileExists(fileName) {
log.Errorf("could not find original for thumbnail: %s", fileName)
c.Data(http.StatusOK, "image/svg+xml", labelIconSvg)

View file

@ -7,9 +7,9 @@ import (
"github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/event"
"github.com/photoprism/photoprism/internal/file"
"github.com/photoprism/photoprism/pkg/fs"
"github.com/photoprism/photoprism/internal/query"
"github.com/photoprism/photoprism/internal/txt"
"github.com/photoprism/photoprism/pkg/txt"
"github.com/gin-gonic/gin"
)
@ -83,7 +83,7 @@ func GetPhotoDownload(router *gin.RouterGroup, conf *config.Config) {
fileName := path.Join(conf.OriginalsPath(), f.FileName)
if !file.Exists(fileName) {
if !fs.FileExists(fileName) {
log.Errorf("could not find original: %s", c.Param("uuid"))
c.Data(404, "image/svg+xml", photoIconSvg)

View file

@ -6,7 +6,7 @@ import (
"github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/query"
"github.com/photoprism/photoprism/internal/txt"
"github.com/photoprism/photoprism/pkg/txt"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"

View file

@ -7,7 +7,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/file"
"github.com/photoprism/photoprism/pkg/fs"
"github.com/photoprism/photoprism/internal/query"
"github.com/photoprism/photoprism/internal/thumb"
)
@ -40,7 +40,7 @@ func GetThumbnail(router *gin.RouterGroup, conf *config.Config) {
fileName := path.Join(conf.OriginalsPath(), f.FileName)
if !file.Exists(fileName) {
if !fs.FileExists(fileName) {
log.Errorf("could not find original for thumbnail: %s", fileName)
c.Data(http.StatusNotFound, "image/svg+xml", photoIconSvg)

View file

@ -12,7 +12,7 @@ import (
"github.com/disintegration/imaging"
"github.com/gin-gonic/gin"
"github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/file"
"github.com/photoprism/photoprism/pkg/fs"
"github.com/photoprism/photoprism/internal/form"
"github.com/photoprism/photoprism/internal/query"
"github.com/photoprism/photoprism/internal/thumb"
@ -33,7 +33,7 @@ func GetPreview(router *gin.RouterGroup, conf *config.Config) {
previewFilename := fmt.Sprintf("%s/%s.jpg", thumbPath, t[6:8])
if file.Exists(previewFilename) {
if fs.FileExists(previewFilename) {
c.File(previewFilename)
return
}
@ -65,7 +65,7 @@ func GetPreview(router *gin.RouterGroup, conf *config.Config) {
for _, f := range p {
fileName := path.Join(conf.OriginalsPath(), f.FileName)
if !file.Exists(fileName) {
if !fs.FileExists(fileName) {
log.Errorf("could not find original for thumbnail: %s", fileName)
c.Data(http.StatusNotFound, "image/svg+xml", photoIconSvg)

View file

@ -7,7 +7,7 @@ import (
"github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/form"
"github.com/photoprism/photoprism/internal/session"
"github.com/photoprism/photoprism/internal/txt"
"github.com/photoprism/photoprism/pkg/txt"
)
// POST /api/v1/session

View file

@ -6,7 +6,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/event"
"github.com/photoprism/photoprism/internal/txt"
"github.com/photoprism/photoprism/pkg/txt"
)
// GET /api/v1/settings

View file

@ -9,7 +9,7 @@ import (
"time"
"github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/txt"
"github.com/photoprism/photoprism/pkg/txt"
"github.com/gin-gonic/gin"
)

View file

@ -11,11 +11,11 @@ import (
"time"
"github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/file"
"github.com/photoprism/photoprism/pkg/fs"
"github.com/photoprism/photoprism/internal/form"
"github.com/photoprism/photoprism/internal/query"
"github.com/photoprism/photoprism/internal/rnd"
"github.com/photoprism/photoprism/internal/txt"
"github.com/photoprism/photoprism/pkg/rnd"
"github.com/photoprism/photoprism/pkg/txt"
"github.com/gin-gonic/gin"
)
@ -74,7 +74,7 @@ func CreateZip(router *gin.RouterGroup, conf *config.Config) {
fileName := path.Join(conf.OriginalsPath(), f.FileName)
fileAlias := f.DownloadFileName()
if file.Exists(fileName) {
if fs.FileExists(fileName) {
if err := addFileToZip(zipWriter, fileName, fileAlias); err != nil {
log.Error(err)
c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{"error": txt.UcFirst("failed to create zip file")})
@ -105,7 +105,7 @@ func DownloadZip(router *gin.RouterGroup, conf *config.Config) {
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", zipBaseName))
if !file.Exists(zipFileName) {
if !fs.FileExists(zipFileName) {
log.Errorf("could not find zip file: %s", zipFileName)
c.Data(404, "image/svg+xml", photoIconSvg)
return

View file

@ -11,7 +11,7 @@ import (
"text/template"
"unicode"
"github.com/photoprism/photoprism/internal/file"
"github.com/photoprism/photoprism/pkg/fs"
"gopkg.in/yaml.v2"
)
@ -30,7 +30,7 @@ func main() {
fileName := "rules.yml"
if !file.Exists(fileName) {
if !fs.FileExists(fileName) {
log.Panicf("tensorflow: label rules file not found in \"%s\"", filepath.Base(fileName))
}

View file

@ -3,7 +3,7 @@ package classify
import (
"sort"
"github.com/photoprism/photoprism/internal/txt"
"github.com/photoprism/photoprism/pkg/txt"
)
// Labels is list of MediaFile labels.

View file

@ -12,14 +12,14 @@ import (
"syscall"
"github.com/photoprism/photoprism/internal/event"
"github.com/photoprism/photoprism/internal/file"
"github.com/photoprism/photoprism/pkg/fs"
"github.com/sevlyar/go-daemon"
)
var log = event.Log
func childAlreadyRunning(filePath string) (pid int, running bool) {
if !file.Exists(filePath) {
if !fs.FileExists(filePath) {
return pid, false
}

View file

@ -10,7 +10,7 @@ import (
"time"
"github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/file"
"github.com/photoprism/photoprism/pkg/fs"
"github.com/photoprism/photoprism/internal/server"
"github.com/sevlyar/go-daemon"
"github.com/urfave/cli"
@ -96,7 +96,7 @@ func startAction(ctx *cli.Context) error {
}
if child != nil {
if !file.Overwrite(conf.PIDFilename(), []byte(strconv.Itoa(child.Pid))) {
if !fs.Overwrite(conf.PIDFilename(), []byte(strconv.Itoa(child.Pid))) {
log.Fatalf("failed writing process id to \"%s\"", conf.PIDFilename())
}

View file

@ -4,9 +4,9 @@ import (
"strings"
"time"
"github.com/photoprism/photoprism/internal/colors"
"github.com/photoprism/photoprism/pkg/colors"
"github.com/photoprism/photoprism/internal/entity"
"github.com/photoprism/photoprism/internal/file"
"github.com/photoprism/photoprism/pkg/fs"
)
// HTTP client / Web UI config values
@ -118,8 +118,8 @@ func (c *Config) ClientConfig() ClientConfig {
categories[i].Title = strings.Title(l.LabelName)
}
jsHash := file.Hash(c.HttpStaticBuildPath() + "/app.js")
cssHash := file.Hash(c.HttpStaticBuildPath() + "/app.css")
jsHash := fs.Hash(c.HttpStaticBuildPath() + "/app.js")
cssHash := fs.Hash(c.HttpStaticBuildPath() + "/app.css")
// Feature Flags
var flags []string

View file

@ -3,7 +3,7 @@ package config
import (
"testing"
"github.com/photoprism/photoprism/internal/file"
"github.com/photoprism/photoprism/pkg/fs"
"github.com/stretchr/testify/assert"
)
@ -17,7 +17,7 @@ func TestNewConfig(t *testing.T) {
assert.IsType(t, new(Config), c)
assert.Equal(t, file.ExpandFilename("../../assets"), c.AssetsPath())
assert.Equal(t, fs.ExpandFilename("../../assets"), c.AssetsPath())
assert.False(t, c.Debug())
assert.False(t, c.ReadOnly())
}

View file

@ -5,7 +5,7 @@ import (
"os/exec"
"path/filepath"
"github.com/photoprism/photoprism/internal/file"
"github.com/photoprism/photoprism/pkg/fs"
)
func findExecutable(configBin, defaultBin string) (result string) {
@ -19,7 +19,7 @@ func findExecutable(configBin, defaultBin string) (result string) {
result = path
}
if !file.Exists(result) {
if !fs.FileExists(result) {
result = ""
}

View file

@ -8,7 +8,7 @@ import (
_ "github.com/jinzhu/gorm/dialects/mysql"
_ "github.com/jinzhu/gorm/dialects/sqlite"
"github.com/photoprism/photoprism/internal/file"
"github.com/photoprism/photoprism/pkg/fs"
"github.com/urfave/cli"
"gopkg.in/yaml.v2"
)
@ -88,7 +88,7 @@ func NewParams(ctx *cli.Context) *Params {
c.Name = ctx.App.Name
c.Copyright = ctx.App.Copyright
c.Version = ctx.App.Version
c.ConfigFile = file.ExpandFilename(ctx.GlobalString("config-file"))
c.ConfigFile = fs.ExpandFilename(ctx.GlobalString("config-file"))
if err := c.SetValuesFromFile(c.ConfigFile); err != nil {
log.Debug(err)
@ -104,21 +104,21 @@ func NewParams(ctx *cli.Context) *Params {
}
func (c *Params) expandFilenames() {
c.ConfigPath = file.ExpandFilename(c.ConfigPath)
c.ResourcesPath = file.ExpandFilename(c.ResourcesPath)
c.AssetsPath = file.ExpandFilename(c.AssetsPath)
c.CachePath = file.ExpandFilename(c.CachePath)
c.OriginalsPath = file.ExpandFilename(c.OriginalsPath)
c.ImportPath = file.ExpandFilename(c.ImportPath)
c.ExportPath = file.ExpandFilename(c.ExportPath)
c.SqlServerPath = file.ExpandFilename(c.SqlServerPath)
c.PIDFilename = file.ExpandFilename(c.PIDFilename)
c.LogFilename = file.ExpandFilename(c.LogFilename)
c.ConfigPath = fs.ExpandFilename(c.ConfigPath)
c.ResourcesPath = fs.ExpandFilename(c.ResourcesPath)
c.AssetsPath = fs.ExpandFilename(c.AssetsPath)
c.CachePath = fs.ExpandFilename(c.CachePath)
c.OriginalsPath = fs.ExpandFilename(c.OriginalsPath)
c.ImportPath = fs.ExpandFilename(c.ImportPath)
c.ExportPath = fs.ExpandFilename(c.ExportPath)
c.SqlServerPath = fs.ExpandFilename(c.SqlServerPath)
c.PIDFilename = fs.ExpandFilename(c.PIDFilename)
c.LogFilename = fs.ExpandFilename(c.LogFilename)
}
// SetValuesFromFile uses a yaml config file to initiate the configuration entity.
func (c *Params) SetValuesFromFile(fileName string) error {
if !file.Exists(fileName) {
if !fs.FileExists(fileName) {
return errors.New(fmt.Sprintf("config file not found: \"%s\"", fileName))
}

View file

@ -3,7 +3,7 @@ package config
import (
"testing"
"github.com/photoprism/photoprism/internal/file"
"github.com/photoprism/photoprism/pkg/fs"
"github.com/stretchr/testify/assert"
)
@ -17,7 +17,7 @@ func TestNewParams(t *testing.T) {
assert.IsType(t, new(Params), c)
assert.Equal(t, file.ExpandFilename("../../assets"), c.AssetsPath)
assert.Equal(t, fs.ExpandFilename("../../assets"), c.AssetsPath)
assert.False(t, c.Debug)
assert.False(t, c.ReadOnly)
}

View file

@ -5,7 +5,7 @@ import (
"io/ioutil"
"os"
"github.com/photoprism/photoprism/internal/file"
"github.com/photoprism/photoprism/pkg/fs"
"gopkg.in/yaml.v2"
)
@ -20,7 +20,7 @@ func NewSettings() *Settings {
// SetValuesFromFile uses a yaml config file to initiate the configuration entity.
func (s *Settings) SetValuesFromFile(fileName string) error {
if !file.Exists(fileName) {
if !fs.FileExists(fileName) {
return fmt.Errorf("settings file not found: \"%s\"", fileName)
}
@ -35,7 +35,7 @@ func (s *Settings) SetValuesFromFile(fileName string) error {
// WriteValuesToFile uses a yaml config file to initiate the configuration entity.
func (s *Settings) WriteValuesToFile(fileName string) error {
if !file.Exists(fileName) {
if !fs.FileExists(fileName) {
return fmt.Errorf("settings file not found: \"%s\"", fileName)
}

View file

@ -10,7 +10,7 @@ import (
_ "github.com/jinzhu/gorm/dialects/mysql"
_ "github.com/jinzhu/gorm/dialects/sqlite"
"github.com/photoprism/photoprism/internal/file"
"github.com/photoprism/photoprism/pkg/fs"
"github.com/photoprism/photoprism/internal/thumb"
"github.com/sirupsen/logrus"
"github.com/urfave/cli"
@ -30,7 +30,7 @@ func testDataPath(assetsPath string) string {
}
func NewTestParams() *Params {
assetsPath := file.ExpandFilename("../../assets")
assetsPath := fs.ExpandFilename("../../assets")
testDataPath := testDataPath(assetsPath)
@ -53,7 +53,7 @@ func NewTestParams() *Params {
}
func NewTestParamsError() *Params {
assetsPath := file.ExpandFilename("../..")
assetsPath := fs.ExpandFilename("../..")
testDataPath := testDataPath("../../assets")
@ -145,8 +145,8 @@ func (c *Config) RemoveTestData(t *testing.T) {
}
func (c *Config) DownloadTestData(t *testing.T) {
if file.Exists(TestDataZip) {
hash := file.Hash(TestDataZip)
if fs.FileExists(TestDataZip) {
hash := fs.Hash(TestDataZip)
if hash != TestDataHash {
os.Remove(TestDataZip)
@ -154,17 +154,17 @@ func (c *Config) DownloadTestData(t *testing.T) {
}
}
if !file.Exists(TestDataZip) {
if !fs.FileExists(TestDataZip) {
fmt.Printf("downloading latest test data zip file from %s\n", TestDataURL)
if err := file.Download(TestDataZip, TestDataURL); err != nil {
if err := fs.Download(TestDataZip, TestDataURL); err != nil {
fmt.Printf("Download failed: %s\n", err.Error())
}
}
}
func (c *Config) UnzipTestData(t *testing.T) {
if _, err := file.Unzip(TestDataZip, testDataPath(c.AssetsPath())); err != nil {
if _, err := fs.Unzip(TestDataZip, testDataPath(c.AssetsPath())); err != nil {
t.Logf("could not unzip test data: %s\n", err.Error())
}
}

View file

@ -4,7 +4,7 @@ import (
"testing"
"github.com/jinzhu/gorm"
"github.com/photoprism/photoprism/internal/file"
"github.com/photoprism/photoprism/pkg/fs"
"github.com/stretchr/testify/assert"
"github.com/urfave/cli"
)
@ -26,7 +26,7 @@ func TestNewTestParams(t *testing.T) {
assert.IsType(t, new(Params), c)
assert.Equal(t, file.ExpandFilename("../../assets"), c.AssetsPath)
assert.Equal(t, fs.ExpandFilename("../../assets"), c.AssetsPath)
assert.False(t, c.Debug)
}
@ -43,7 +43,7 @@ func TestNewTestParamsError(t *testing.T) {
assert.IsType(t, new(Params), c)
assert.Equal(t, file.ExpandFilename("../.."), c.AssetsPath)
assert.Equal(t, fs.ExpandFilename("../.."), c.AssetsPath)
assert.Equal(t, "../../assets/testdata/cache", c.CachePath)
assert.False(t, c.Debug)
}

View file

@ -6,7 +6,7 @@ import (
"github.com/gosimple/slug"
"github.com/jinzhu/gorm"
"github.com/photoprism/photoprism/internal/rnd"
"github.com/photoprism/photoprism/pkg/rnd"
)
// Photo album

View file

@ -4,7 +4,7 @@ import (
"time"
"github.com/jinzhu/gorm"
"github.com/photoprism/photoprism/internal/rnd"
"github.com/photoprism/photoprism/pkg/rnd"
)
// Events

View file

@ -7,7 +7,7 @@ import (
"github.com/gosimple/slug"
"github.com/jinzhu/gorm"
"github.com/photoprism/photoprism/internal/rnd"
"github.com/photoprism/photoprism/pkg/rnd"
)
// An image or sidecar file that belongs to a photo

View file

@ -7,7 +7,7 @@ import (
"github.com/gosimple/slug"
"github.com/jinzhu/gorm"
"github.com/photoprism/photoprism/internal/mutex"
"github.com/photoprism/photoprism/internal/rnd"
"github.com/photoprism/photoprism/pkg/rnd"
)
// Labels for photo, album and location categorization

View file

@ -8,8 +8,8 @@ import (
"github.com/jinzhu/gorm"
"github.com/photoprism/photoprism/internal/maps"
"github.com/photoprism/photoprism/internal/mutex"
"github.com/photoprism/photoprism/internal/s2"
"github.com/photoprism/photoprism/internal/txt"
"github.com/photoprism/photoprism/pkg/s2"
"github.com/photoprism/photoprism/pkg/txt"
)
var locationMutex = sync.Mutex{}

View file

@ -5,8 +5,8 @@ import (
"time"
"github.com/jinzhu/gorm"
"github.com/photoprism/photoprism/internal/rnd"
"github.com/photoprism/photoprism/internal/txt"
"github.com/photoprism/photoprism/pkg/rnd"
"github.com/photoprism/photoprism/pkg/txt"
)
// A photo can have multiple images and sidecar files

View file

@ -4,7 +4,7 @@ import (
"time"
"github.com/jinzhu/gorm"
"github.com/photoprism/photoprism/internal/rnd"
"github.com/photoprism/photoprism/pkg/rnd"
)
// Shared photos and/or albums

View file

@ -5,7 +5,7 @@ import (
"testing"
"github.com/photoprism/photoprism/internal/maps/osm"
"github.com/photoprism/photoprism/internal/s2"
"github.com/photoprism/photoprism/pkg/s2"
"github.com/stretchr/testify/assert"
)

View file

@ -9,8 +9,8 @@ import (
"time"
"github.com/melihmucuk/geocache"
"github.com/photoprism/photoprism/internal/s2"
"github.com/photoprism/photoprism/internal/txt"
"github.com/photoprism/photoprism/pkg/s2"
"github.com/photoprism/photoprism/pkg/txt"
)
type Location struct {

View file

@ -5,7 +5,7 @@ package osm
import (
"testing"
"github.com/photoprism/photoprism/internal/s2"
"github.com/photoprism/photoprism/pkg/s2"
"github.com/stretchr/testify/assert"
)

View file

@ -3,7 +3,7 @@ package osm
import (
"strings"
"github.com/photoprism/photoprism/internal/txt"
"github.com/photoprism/photoprism/pkg/txt"
)
var labelTitles = map[string]string{

View file

@ -6,8 +6,8 @@ import (
"net/http"
gc "github.com/patrickmn/go-cache"
"github.com/photoprism/photoprism/internal/s2"
"github.com/photoprism/photoprism/internal/txt"
"github.com/photoprism/photoprism/pkg/s2"
"github.com/photoprism/photoprism/pkg/txt"
)
// Location

View file

@ -3,7 +3,7 @@ package places
import (
"testing"
"github.com/photoprism/photoprism/internal/s2"
"github.com/photoprism/photoprism/pkg/s2"
"github.com/stretchr/testify/assert"
)

View file

@ -9,7 +9,7 @@ import (
"path/filepath"
"sync"
"github.com/photoprism/photoprism/internal/file"
"github.com/photoprism/photoprism/pkg/fs"
tf "github.com/tensorflow/tensorflow/tensorflow/go"
"github.com/tensorflow/tensorflow/tensorflow/go/op"
)
@ -30,7 +30,7 @@ func New(modelPath string) *Detector {
// File returns matching labels for a jpeg media file.
func (t *Detector) File(filename string) (result Labels, err error) {
if file.MimeType(filename) != "image/jpeg" {
if fs.MimeType(filename) != "image/jpeg" {
return result, fmt.Errorf("nsfw: \"%s\" is not a jpeg file", filename)
}

View file

@ -6,7 +6,7 @@ import (
"math"
"github.com/lucasb-eyer/go-colorful"
"github.com/photoprism/photoprism/internal/colors"
"github.com/photoprism/photoprism/pkg/colors"
)
// Colors returns the ColorPerception of an image (only JPEG supported).

View file

@ -6,7 +6,7 @@ import (
"strings"
"testing"
"github.com/photoprism/photoprism/internal/colors"
"github.com/photoprism/photoprism/pkg/colors"
"github.com/photoprism/photoprism/internal/config"
"github.com/stretchr/testify/assert"
)

View file

@ -5,7 +5,7 @@ import (
"testing"
"github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/file"
"github.com/photoprism/photoprism/pkg/fs"
"github.com/stretchr/testify/assert"
)
@ -30,7 +30,7 @@ func TestConvert_ToJpeg(t *testing.T) {
jpegFilename := conf.ImportPath() + "/fern_green.jpg"
assert.Truef(t, file.Exists(jpegFilename), "file does not exist: %s", jpegFilename)
assert.Truef(t, fs.FileExists(jpegFilename), "file does not exist: %s", jpegFilename)
t.Logf("Testing RAW to JPEG convert with %s", jpegFilename)
@ -64,7 +64,7 @@ func TestConvert_ToJpeg(t *testing.T) {
imageRaw, _ := convert.ToJpeg(rawMediaFile)
assert.True(t, file.Exists(conf.ImportPath()+"/raw/IMG_2567.jpg"), "Jpeg file was not found - is Darktable installed?")
assert.True(t, fs.FileExists(conf.ImportPath()+"/raw/IMG_2567.jpg"), "Jpeg file was not found - is Darktable installed?")
assert.NotEqual(t, rawFilename, imageRaw.filename)
@ -88,7 +88,7 @@ func TestConvert_Start(t *testing.T) {
jpegFilename := conf.ImportPath() + "/raw/canon_eos_6d.jpg"
assert.True(t, file.Exists(jpegFilename), "Jpeg file was not found - is Darktable installed?")
assert.True(t, fs.FileExists(jpegFilename), "Jpeg file was not found - is Darktable installed?")
image, err := NewMediaFile(jpegFilename)
@ -104,15 +104,15 @@ func TestConvert_Start(t *testing.T) {
existingJpegFilename := conf.ImportPath() + "/raw/IMG_2567.jpg"
oldHash := file.Hash(existingJpegFilename)
oldHash := fs.Hash(existingJpegFilename)
os.Remove(existingJpegFilename)
convert.Start(conf.ImportPath())
newHash := file.Hash(existingJpegFilename)
newHash := fs.Hash(existingJpegFilename)
assert.True(t, file.Exists(existingJpegFilename), "Jpeg file was not found - is Darktable installed?")
assert.True(t, fs.FileExists(existingJpegFilename), "Jpeg file was not found - is Darktable installed?")
assert.NotEqual(t, oldHash, newHash, "Fingerprint of old and new JPEG file must not be the same")
}

View file

@ -12,7 +12,7 @@ import (
"github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/entity"
"github.com/photoprism/photoprism/internal/event"
"github.com/photoprism/photoprism/internal/file"
"github.com/photoprism/photoprism/pkg/fs"
"github.com/photoprism/photoprism/internal/mutex"
)
@ -158,7 +158,7 @@ func (imp *Import) Start(importPath string) {
if imp.removeEmptyDirectories {
// Remove empty directories from import path
for _, directory := range directories {
if file.IsEmpty(directory) {
if fs.IsEmpty(directory) {
if err := os.Remove(directory); err != nil {
log.Errorf("import: could not deleted empty directory \"%s\" (%s)", directory, err)
} else {
@ -196,8 +196,8 @@ func (imp *Import) DestinationFilename(mainFile *MediaFile, mediaFile *MediaFile
result := pathName + string(os.PathSeparator) + fileName + fileExtension
for file.Exists(result) {
if mediaFile.Hash() == file.Hash(result) {
for fs.FileExists(result) {
if mediaFile.Hash() == fs.Hash(result) {
return result, fmt.Errorf("file already exists: %s", result)
}

View file

@ -13,7 +13,7 @@ import (
"github.com/photoprism/photoprism/internal/entity"
"github.com/photoprism/photoprism/internal/event"
"github.com/photoprism/photoprism/internal/meta"
"github.com/photoprism/photoprism/internal/txt"
"github.com/photoprism/photoprism/pkg/txt"
)
const (

View file

@ -4,7 +4,7 @@ import (
"sort"
"strings"
"github.com/photoprism/photoprism/internal/txt"
"github.com/photoprism/photoprism/pkg/txt"
)
// Label represents a MediaFile label (automatically created).

View file

@ -16,7 +16,7 @@ import (
"github.com/djherbis/times"
"github.com/photoprism/photoprism/internal/capture"
"github.com/photoprism/photoprism/internal/entity"
"github.com/photoprism/photoprism/internal/file"
"github.com/photoprism/photoprism/pkg/fs"
"github.com/photoprism/photoprism/internal/meta"
"github.com/photoprism/photoprism/internal/thumb"
)
@ -27,7 +27,7 @@ type MediaFile struct {
dateCreated time.Time
timeZone string
hash string
fileType file.Type
fileType fs.Type
mimeType string
perceptualHash string
width int
@ -39,13 +39,13 @@ type MediaFile struct {
// NewMediaFile returns a new MediaFile.
func NewMediaFile(filename string) (*MediaFile, error) {
if !file.Exists(filename) {
if !fs.FileExists(filename) {
return nil, fmt.Errorf("file does not exist: %s", filename)
}
instance := &MediaFile{
filename: filename,
fileType: file.TypeOther,
fileType: fs.TypeOther,
}
return instance, nil
@ -241,7 +241,7 @@ func (m *MediaFile) CanonicalNameFromFileWithDirectory() string {
// Hash return a sha1 hash of a MediaFile based on the filename.
func (m *MediaFile) Hash() string {
if len(m.hash) == 0 {
m.hash = file.Hash(m.Filename())
m.hash = fs.Hash(m.Filename())
}
return m.hash
@ -252,7 +252,7 @@ func (m *MediaFile) EditedFilename() string {
basename := filepath.Base(m.filename)
if strings.ToUpper(basename[:4]) == "IMG_" && strings.ToUpper(basename[:5]) != "IMG_E" {
if filename := filepath.Dir(m.filename) + string(os.PathSeparator) + basename[:4] + "E" + basename[4:]; file.Exists(filename) {
if filename := filepath.Dir(m.filename) + string(os.PathSeparator) + basename[:4] + "E" + basename[4:]; fs.FileExists(filename) {
return filename
}
}
@ -393,7 +393,7 @@ func (m *MediaFile) MimeType() string {
return m.mimeType
}
m.mimeType = file.MimeType(m.Filename())
m.mimeType = fs.MimeType(m.Filename())
return m.mimeType
}
@ -409,7 +409,7 @@ func (m *MediaFile) openFile() (*os.File, error) {
// Exists checks if a media file exists by filename.
func (m *MediaFile) Exists() bool {
return file.Exists(m.Filename())
return fs.FileExists(m.Filename())
}
// Remove a media file.
@ -488,17 +488,17 @@ func (m *MediaFile) IsJpeg() bool {
return false
}
return m.MimeType() == file.MimeTypeJpeg
return m.MimeType() == fs.MimeTypeJpeg
}
// Type returns the type of the media file.
func (m *MediaFile) Type() file.Type {
return file.Ext[m.Extension()]
func (m *MediaFile) Type() fs.Type {
return fs.Ext[m.Extension()]
}
// HasType returns true if this media file is of a given type.
func (m *MediaFile) HasType(t file.Type) bool {
if t == file.TypeJpeg {
func (m *MediaFile) HasType(t fs.Type) bool {
if t == fs.TypeJpeg {
return m.IsJpeg()
}
@ -507,29 +507,29 @@ func (m *MediaFile) HasType(t file.Type) bool {
// IsRaw returns true if this media file a RAW file.
func (m *MediaFile) IsRaw() bool {
return m.HasType(file.TypeRaw)
return m.HasType(fs.TypeRaw)
}
// IsPng returns true if this media file a PNG file.
func (m *MediaFile) IsPng() bool {
return m.HasType(file.TypePng)
return m.HasType(fs.TypePng)
}
// IsTiff returns true if this media file a TIFF file.
func (m *MediaFile) IsTiff() bool {
return m.HasType(file.TypeTiff)
return m.HasType(fs.TypeTiff)
}
// IsImageOther returns true this media file a PNG, GIF, BMP or TIFF file.
func (m *MediaFile) IsImageOther() bool {
switch m.Type() {
case file.TypeBitmap:
case fs.TypeBitmap:
return true
case file.TypeGif:
case fs.TypeGif:
return true
case file.TypePng:
case fs.TypePng:
return true
case file.TypeTiff:
case fs.TypeTiff:
return true
default:
return false
@ -538,23 +538,23 @@ func (m *MediaFile) IsImageOther() bool {
// IsHEIF returns true if this media file is a High Efficiency Image File Format file.
func (m *MediaFile) IsHEIF() bool {
return m.HasType(file.TypeHEIF)
return m.HasType(fs.TypeHEIF)
}
// IsSidecar returns true if this media file is a sidecar file (containing metadata).
func (m *MediaFile) IsSidecar() bool {
switch m.Type() {
case file.TypeXMP:
case fs.TypeXMP:
return true
case file.TypeAAE:
case fs.TypeAAE:
return true
case file.TypeXML:
case fs.TypeXML:
return true
case file.TypeYaml:
case fs.TypeYaml:
return true
case file.TypeText:
case fs.TypeText:
return true
case file.TypeMarkdown:
case fs.TypeMarkdown:
return true
default:
return false
@ -564,7 +564,7 @@ func (m *MediaFile) IsSidecar() bool {
// IsVideo returns true if this media file is a video file.
func (m *MediaFile) IsVideo() bool {
switch m.Type() {
case file.TypeMovie:
case fs.TypeMovie:
return true
}
@ -582,9 +582,9 @@ func (m *MediaFile) Jpeg() (*MediaFile, error) {
return m, nil
}
jpegFilename := fmt.Sprintf("%s.%s", m.DirectoryBasename(), file.TypeJpeg)
jpegFilename := fmt.Sprintf("%s.%s", m.DirectoryBasename(), fs.TypeJpeg)
if !file.Exists(jpegFilename) {
if !fs.FileExists(jpegFilename) {
return nil, fmt.Errorf("jpeg file does not exist: %s", jpegFilename)
}
@ -742,7 +742,7 @@ func (m *MediaFile) CreateDefaultThumbnails(thumbPath string, force bool) (err e
return err
} else {
if !force && file.Exists(fileName) {
if !force && fs.FileExists(fileName) {
continue
}

View file

@ -4,7 +4,7 @@ import (
"os"
"testing"
"github.com/photoprism/photoprism/internal/file"
"github.com/photoprism/photoprism/pkg/fs"
"github.com/photoprism/photoprism/internal/thumb"
"github.com/photoprism/photoprism/internal/config"
@ -515,7 +515,7 @@ func TestMediaFile_Move(t *testing.T) {
f, err := NewMediaFile(conf.ExamplesPath() + "/table_white.jpg")
assert.Nil(t, err)
f.Copy(origName)
assert.True(t, file.Exists(origName))
assert.True(t, fs.FileExists(origName))
m, err := NewMediaFile(origName)
assert.Nil(t, err)
@ -524,7 +524,7 @@ func TestMediaFile_Move(t *testing.T) {
t.Errorf("failed to move: %s", err)
}
assert.True(t, file.Exists(destName))
assert.True(t, fs.FileExists(destName))
assert.Equal(t, destName, m.Filename())
}
@ -540,7 +540,7 @@ func TestMediaFile_Copy(t *testing.T) {
mediaFile, err := NewMediaFile(conf.ExamplesPath() + "/table_white.jpg")
assert.Nil(t, err)
mediaFile.Copy(tmpPath + "table_whitecopy.jpg")
assert.True(t, file.Exists(tmpPath+"table_whitecopy.jpg"))
assert.True(t, fs.FileExists(tmpPath+"table_whitecopy.jpg"))
}
func TestMediaFile_Extension(t *testing.T) {

View file

@ -1,14 +0,0 @@
/*
Package config contains random token functions.
Additional information can be found in our Developer Guide:
https://github.com/photoprism/photoprism/wiki
*/
package rnd
import (
"github.com/photoprism/photoprism/internal/event"
)
var log = event.Log

View file

@ -9,20 +9,20 @@ import (
"path"
"path/filepath"
"github.com/photoprism/photoprism/internal/file"
"github.com/photoprism/photoprism/pkg/fs"
"github.com/disintegration/imaging"
)
func ResampleOptions(opts ...ResampleOption) (method ResampleOption, filter imaging.ResampleFilter, format file.Type) {
func ResampleOptions(opts ...ResampleOption) (method ResampleOption, filter imaging.ResampleFilter, format fs.Type) {
method = ResampleFit
filter = imaging.Lanczos
format = file.TypeJpeg
format = fs.TypeJpeg
for _, option := range opts {
switch option {
case ResamplePng:
format = file.TypePng
format = fs.TypePng
case ResampleNearestNeighbor:
filter = imaging.NearestNeighbor
case ResampleLanczos:
@ -116,7 +116,7 @@ func FromFile(imageFilename string, hash string, thumbPath string, width, height
return "", err
}
if file.Exists(fileName) {
if fs.FileExists(fileName) {
return fileName, nil
}
@ -147,7 +147,7 @@ func Create(img image.Image, fileName string, width, height int, opts ...Resampl
var saveOption imaging.EncodeOption
if filepath.Ext(fileName) == "."+string(file.TypePng) {
if filepath.Ext(fileName) == "."+string(fs.TypePng) {
saveOption = imaging.PNGCompressionLevel(png.DefaultCompression)
} else if width <= 150 && height <= 150 {
saveOption = imaging.JPEGQuality(JpegQualitySmall)

File diff suppressed because it is too large Load diff

View file

@ -1,19 +0,0 @@
package txt
import (
"bytes"
"os"
"testing"
"github.com/sirupsen/logrus"
)
var logBuffer bytes.Buffer
func TestMain(m *testing.M) {
log = logrus.StandardLogger()
log.Out = &logBuffer
log.SetLevel(logrus.DebugLevel)
code := m.Run()
os.Exit(code)
}

View file

@ -1,5 +1,5 @@
/*
This package encapsulates color classification.
Package colors provides types and functions for color classification.
Additional information can be found in our Developer Guide:
@ -15,6 +15,7 @@ import (
"github.com/lucasb-eyer/go-colorful"
)
// TODO: Requires documentation
type ColorPerception struct {
Colors Colors
MainColor Color

View file

@ -1,11 +1,11 @@
/*
This package encapsulates file related constants and functions.
Package fs provides filesystem related constants and functions.
Additional information can be found in our Developer Guide:
https://github.com/photoprism/photoprism/wiki
*/
package file
package fs
import (
"archive/zip"
@ -16,14 +16,10 @@ import (
"os/user"
"path/filepath"
"strings"
"github.com/photoprism/photoprism/internal/event"
)
var log = event.Log
// Returns true if file exists
func Exists(filename string) bool {
// FileExists returns true if file exists (false for directories).
func FileExists(filename string) bool {
info, err := os.Stat(filename)
return err == nil && !info.IsDir()
@ -40,7 +36,7 @@ func Overwrite(fileName string, data []byte) bool {
return err == nil
}
// Returns full path; ~ replaced with actual home directory
// Returns full path of a file, "~" is replaced with home directory
func ExpandFilename(filename string) string {
if filename == "" {
return ""
@ -104,7 +100,7 @@ func copyToFile(f *zip.File, dest string) (fileName string, err error) {
return fileName, nil
}
// Download a file from a URL
// Download downloads a file from a URL.
func Download(filepath string, url string) error {
os.MkdirAll("/tmp/photoprism", os.ModePerm)
@ -136,6 +132,7 @@ func Download(filepath string, url string) error {
return nil
}
// IsEmpty returns true if a directory is empty.
func IsEmpty(path string) bool {
f, err := os.Open(path)

View file

@ -1,4 +1,4 @@
package file
package fs
import (
"os"
@ -9,8 +9,8 @@ import (
)
func TestExists(t *testing.T) {
assert.True(t, Exists("./testdata/test.jpg"))
assert.False(t, Exists("./foo.jpg"))
assert.True(t, FileExists("./testdata/test.jpg"))
assert.False(t, FileExists("./foo.jpg"))
}
func TestOverwrite(t *testing.T) {

View file

@ -1,4 +1,4 @@
package file
package fs
import (
"crypto/sha1"
@ -7,7 +7,7 @@ import (
"os"
)
// Returns sha1 hash of file as string
// Hash returns the sha1 hash of file as string.
func Hash(filename string) string {
var result []byte

View file

@ -1,4 +1,4 @@
package file
package fs
import (
"testing"

View file

@ -1,15 +1,15 @@
package file
package fs
import (
"net/http"
"os"
)
// MimeType returns the mime type of a file, empty string if unknown.
func MimeType(filename string) string {
handle, err := os.Open(filename)
if err != nil {
log.Error(err.Error())
return ""
}
@ -21,7 +21,6 @@ func MimeType(filename string) string {
_, err = handle.Read(buffer)
if err != nil {
log.Errorf("could not read file to determine mime type: %s", filename)
return ""
}

View file

@ -1,4 +1,4 @@
package file
package fs
import (
"testing"

View file

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View file

@ -1,4 +1,4 @@
package file
package fs
import (
_ "image/gif" // Import for image.
@ -42,11 +42,10 @@ const (
)
const (
// MimeTypeJpeg is jpeg image type
MimeTypeJpeg = "image/jpeg"
)
// Ext lists all the available and supported image file formats.
// Ext contains the filename extensions of file formats known to PhotoPrism.
var Ext = map[string]Type{
".bmp": TypeBitmap,
".gif": TypeGif,

View file

@ -1,4 +1,4 @@
package file
package fs
import (
"archive/zip"

6
pkg/rnd/password.go Normal file
View file

@ -0,0 +1,6 @@
package rnd
// Password returns a random password with 8 characters as string.
func Password() string {
return Token(8)
}

16
pkg/rnd/ppid.go Normal file
View file

@ -0,0 +1,16 @@
package rnd
import (
"strconv"
"time"
)
// PPID returns a unique id with prefix as string.
func PPID(prefix rune) string {
result := make([]byte, 0, 17)
result = append(result, byte(prefix))
result = append(result, strconv.FormatInt(time.Now().UTC().Unix(), 36)[0:6]...)
result = append(result, Token(10)...)
return string(result)
}

8
pkg/rnd/rnd.go Normal file
View file

@ -0,0 +1,8 @@
/*
Package rnd provides random token functions.
Additional information can be found in our Developer Guide:
https://github.com/photoprism/photoprism/wiki
*/
package rnd

View file

@ -3,22 +3,21 @@ package rnd
import (
"crypto/rand"
"encoding/binary"
"fmt"
"strconv"
"time"
uuid "github.com/satori/go.uuid"
)
// Token returns a random token with length of up to 10 characters.
func Token(size uint) string {
if size > 10 || size < 1 {
log.Fatalf("size out of range: %d", size)
panic(fmt.Sprintf("size out of range: %d", size))
}
result := make([]byte, 0, 14)
b := make([]byte, 8)
if _, err := rand.Read(b); err != nil {
log.Fatal(err)
panic(err)
}
randomInt := binary.BigEndian.Uint64(b)
@ -31,20 +30,3 @@ func Token(size uint) string {
return string(result[:size])
}
func Password() string {
return Token(8)
}
func PPID(prefix rune) string {
result := make([]byte, 0, 17)
result = append(result, byte(prefix))
result = append(result, strconv.FormatInt(time.Now().UTC().Unix(), 36)[0:6]...)
result = append(result, Token(10)...)
return string(result)
}
func UUID() string {
return uuid.NewV4().String()
}

10
pkg/rnd/uuid.go Normal file
View file

@ -0,0 +1,10 @@
package rnd
import (
uuid "github.com/satori/go.uuid"
)
// UUID returns a standard, random UUID as string.
func UUID() string {
return uuid.NewV4().String()
}

View file

@ -1,30 +1,40 @@
/*
Package s2 encapsulates Google's S2 library.
Additional information can be found in our Developer Guide:
https://github.com/photoprism/photoprism/wiki
...and in the Google S2 documentation:
https://s2geometry.io/
*/
package s2
import (
gs2 "github.com/golang/geo/s2"
"github.com/photoprism/photoprism/internal/event"
)
var log = event.Log
var Level = 21
// Default cell level, see https://s2geometry.io/resources/s2cell_statistics.html.
var DefaultLevel = 21
// Token returns the S2 cell token for coordinates using the default level.
func Token(lat, lng float64) string {
return TokenLevel(lat, lng, Level)
return TokenLevel(lat, lng, DefaultLevel)
}
// Token returns the S2 cell token for coordinates.
func TokenLevel(lat, lng float64, level int) string {
if lat == 0.0 && lng == 0.0 {
log.Debugf("s2: no values for latitude and longitude")
return ""
}
if lat < -90 || lat > 90 {
log.Warnf("s2: latitude out of range (%f)", lat)
return ""
}
if lng < -180 || lng > 180 {
log.Warnf("s2: longitude out of range (%f)", lng)
return ""
}
@ -32,9 +42,9 @@ func TokenLevel(lat, lng float64, level int) string {
return gs2.CellIDFromLatLng(l).Parent(level).ToToken()
}
// LatLng returns the coordinates for a S2 cell token.
func LatLng(token string) (lat, lng float64) {
if token == "" || token == "-" {
log.Warn("s2: empty token")
return 0.0, 0.0
}

View file

@ -87,3 +87,11 @@ func TestTokenLevel(t *testing.T) {
assert.Equal(t, expected, token)
})
}
func TestLatLng(t *testing.T) {
t.Run("Wildgehege", func(t *testing.T) {
lat, lng := LatLng("4799e370ca54c8b9")
assert.Equal(t, 48.56344835921243, lat)
assert.Equal(t, 8.996878323369781, lng)
})
}

View file

@ -1,5 +1,6 @@
package txt
// Months contains all month names in English.
var Months = [...]string{
"Unknown",
"January",

View file

@ -48,8 +48,9 @@ func main() {
}
var packageTemplate = template.Must(template.New("").Parse(`// Code generated by go generate; DO NOT EDIT.
package util
package txt
// Stopwords contains a list of stopwords for full-text indexing.
var Stopwords = map[string]bool{
{{- range .Words }}
{{ printf "%q" . }}: true,

View file

@ -7,6 +7,7 @@ import (
var KeywordsRegexp = regexp.MustCompile("[\\p{L}]{3,}")
// Keywords extracts keywords for indexing and returns them as string slice.
func Keywords(s string) (results []string) {
all := KeywordsRegexp.FindAllString(s, -1)

4984
pkg/txt/stopwords.go Normal file

File diff suppressed because it is too large Load diff

View file

@ -8,6 +8,7 @@ import (
var ContainsNumberRegexp = regexp.MustCompile("\\d+")
// ContainsNumber returns true if string contains a number.
func ContainsNumber(s string) bool {
return ContainsNumberRegexp.MatchString(s)
}
@ -36,6 +37,7 @@ func isSeparator(r rune) bool {
return unicode.IsSpace(r)
}
// UcFirst returns the string with the first character converted to uppercase.
func UcFirst(str string) string {
for i, v := range str {
return string(unicode.ToUpper(v)) + str[i+1:]
@ -43,6 +45,7 @@ func UcFirst(str string) string {
return ""
}
// Title returns the string with all the first character of each word converted to uppercase.
func Title(s string) string {
prev := ' '
return strings.Map(

View file

@ -1,5 +1,6 @@
package txt
// List of titles and ranks in lowercase, see https://en.wikipedia.org/wiki/List_of_titles.
var TitlesAndRanks = map[string]bool {
"emperor": true,
"caliph": true,

View file

@ -1,5 +1,5 @@
/*
Package txt contains text / linguistics related code.
Package txt provides text / linguistics related functionality.
Additional information can be found in our Developer Guide:
@ -7,10 +7,4 @@ https://github.com/photoprism/photoprism/wiki
*/
package txt
import (
"github.com/photoprism/photoprism/internal/event"
)
//go:generate go run gen.go
var log = event.Log