2019-11-12 04:34:37 +01:00
|
|
|
package config
|
|
|
|
|
2019-11-17 03:08:13 +01:00
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"os"
|
|
|
|
|
2020-12-16 11:59:16 +01:00
|
|
|
"github.com/photoprism/photoprism/internal/entity"
|
|
|
|
|
2020-07-04 12:54:35 +02:00
|
|
|
"github.com/photoprism/photoprism/internal/i18n"
|
2020-01-12 14:00:56 +01:00
|
|
|
"github.com/photoprism/photoprism/pkg/fs"
|
2021-12-14 20:01:39 +01:00
|
|
|
"github.com/photoprism/photoprism/pkg/sanitize"
|
2019-11-17 03:08:13 +01:00
|
|
|
"gopkg.in/yaml.v2"
|
|
|
|
)
|
|
|
|
|
2020-12-13 14:53:26 +01:00
|
|
|
// UISettings represents user interface settings.
|
|
|
|
type UISettings struct {
|
2020-12-18 09:11:42 +01:00
|
|
|
Scrollbar bool `json:"scrollbar" yaml:"Scrollbar"`
|
2021-01-04 19:08:44 +01:00
|
|
|
Zoom bool `json:"zoom" yaml:"Zoom"`
|
2020-12-18 09:11:42 +01:00
|
|
|
Theme string `json:"theme" yaml:"Theme"`
|
|
|
|
Language string `json:"language" yaml:"Language"`
|
2020-12-13 14:53:26 +01:00
|
|
|
}
|
|
|
|
|
2022-03-30 20:36:25 +02:00
|
|
|
// SearchSettings represents search UI preferences.
|
|
|
|
type SearchSettings struct {
|
|
|
|
BatchSize int `json:"batchSize" yaml:"BatchSize"`
|
|
|
|
PrefetchDist int `json:"prefetchDist" yaml:"PrefetchDist"`
|
|
|
|
}
|
|
|
|
|
2020-12-13 14:53:26 +01:00
|
|
|
// TemplateSettings represents template settings for the UI and messaging.
|
2020-05-05 18:26:44 +02:00
|
|
|
type TemplateSettings struct {
|
2020-12-18 09:11:42 +01:00
|
|
|
Default string `json:"default" yaml:"Default"`
|
2020-05-05 18:26:44 +02:00
|
|
|
}
|
|
|
|
|
2020-09-06 14:18:40 +02:00
|
|
|
// MapsSettings represents maps settings (for places).
|
2020-03-31 18:56:52 +02:00
|
|
|
type MapsSettings struct {
|
2020-12-18 09:11:42 +01:00
|
|
|
Animate int `json:"animate" yaml:"Animate"`
|
|
|
|
Style string `json:"style" yaml:"Style"`
|
2020-03-31 18:56:52 +02:00
|
|
|
}
|
|
|
|
|
2020-09-06 14:18:40 +02:00
|
|
|
// FeatureSettings represents feature flags, mainly for the Web UI.
|
2020-04-13 18:08:21 +02:00
|
|
|
type FeatureSettings struct {
|
2020-12-30 11:11:58 +01:00
|
|
|
Upload bool `json:"upload" yaml:"Upload"`
|
|
|
|
Download bool `json:"download" yaml:"Download"`
|
|
|
|
Private bool `json:"private" yaml:"Private"`
|
|
|
|
Review bool `json:"review" yaml:"Review"`
|
|
|
|
Files bool `json:"files" yaml:"Files"`
|
2021-02-08 09:04:44 +01:00
|
|
|
Videos bool `json:"videos" yaml:"Videos"`
|
2020-12-30 18:10:20 +01:00
|
|
|
Folders bool `json:"folders" yaml:"Folders"`
|
2021-01-04 19:08:44 +01:00
|
|
|
Albums bool `json:"albums" yaml:"Albums"`
|
2020-12-30 11:11:58 +01:00
|
|
|
Moments bool `json:"moments" yaml:"Moments"`
|
|
|
|
Estimates bool `json:"estimates" yaml:"Estimates"`
|
2021-01-04 19:08:44 +01:00
|
|
|
People bool `json:"people" yaml:"People"`
|
2020-12-30 11:11:58 +01:00
|
|
|
Labels bool `json:"labels" yaml:"Labels"`
|
|
|
|
Places bool `json:"places" yaml:"Places"`
|
|
|
|
Edit bool `json:"edit" yaml:"Edit"`
|
|
|
|
Archive bool `json:"archive" yaml:"Archive"`
|
|
|
|
Delete bool `json:"delete" yaml:"Delete"`
|
|
|
|
Share bool `json:"share" yaml:"Share"`
|
|
|
|
Library bool `json:"library" yaml:"Library"`
|
|
|
|
Import bool `json:"import" yaml:"Import"`
|
|
|
|
Logs bool `json:"logs" yaml:"Logs"`
|
2020-04-12 18:00:31 +02:00
|
|
|
}
|
|
|
|
|
2020-12-07 16:19:03 +01:00
|
|
|
// ImportSettings represents import settings.
|
|
|
|
type ImportSettings struct {
|
2020-12-18 09:11:42 +01:00
|
|
|
Path string `json:"path" yaml:"Path"`
|
|
|
|
Move bool `json:"move" yaml:"Move"`
|
2020-12-07 16:19:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// IndexSettings represents indexing settings.
|
|
|
|
type IndexSettings struct {
|
2020-12-18 09:11:42 +01:00
|
|
|
Path string `json:"path" yaml:"Path"`
|
|
|
|
Convert bool `json:"convert" yaml:"Convert"`
|
|
|
|
Rescan bool `json:"rescan" yaml:"Rescan"`
|
2020-12-07 16:19:03 +01:00
|
|
|
}
|
|
|
|
|
2020-12-07 17:03:06 +01:00
|
|
|
// StackSettings represents settings for files that belong to the same photo.
|
2020-12-07 16:19:03 +01:00
|
|
|
type StackSettings struct {
|
2020-12-18 09:11:42 +01:00
|
|
|
UUID bool `json:"uuid" yaml:"UUID"`
|
|
|
|
Meta bool `json:"meta" yaml:"Meta"`
|
|
|
|
Name bool `json:"name" yaml:"Name"`
|
2020-12-07 16:19:03 +01:00
|
|
|
}
|
|
|
|
|
2020-12-16 11:59:16 +01:00
|
|
|
// ShareSettings represents content sharing settings.
|
2020-12-13 14:53:26 +01:00
|
|
|
type ShareSettings struct {
|
2020-12-18 09:11:42 +01:00
|
|
|
Title string `json:"title" yaml:"Title"`
|
2020-12-13 14:53:26 +01:00
|
|
|
}
|
|
|
|
|
2020-12-16 11:59:16 +01:00
|
|
|
// DownloadSettings represents content download settings.
|
|
|
|
type DownloadSettings struct {
|
2020-12-18 09:11:42 +01:00
|
|
|
Name entity.DownloadName `json:"name" yaml:"Name"`
|
2020-12-16 11:59:16 +01:00
|
|
|
}
|
|
|
|
|
2020-09-06 14:18:40 +02:00
|
|
|
// Settings represents user settings for Web UI, indexing, and import.
|
2019-11-12 04:34:37 +01:00
|
|
|
type Settings struct {
|
2020-12-18 09:11:42 +01:00
|
|
|
UI UISettings `json:"ui" yaml:"UI"`
|
2022-03-30 20:36:25 +02:00
|
|
|
Search SearchSettings `json:"search" yaml:"Search"`
|
2020-12-18 09:11:42 +01:00
|
|
|
Maps MapsSettings `json:"maps" yaml:"Maps"`
|
|
|
|
Features FeatureSettings `json:"features" yaml:"Features"`
|
|
|
|
Import ImportSettings `json:"import" yaml:"Import"`
|
|
|
|
Index IndexSettings `json:"index" yaml:"Index"`
|
|
|
|
Stack StackSettings `json:"stack" yaml:"Stack"`
|
|
|
|
Share ShareSettings `json:"share" yaml:"Share"`
|
|
|
|
Download DownloadSettings `json:"download" yaml:"Download"`
|
2022-03-30 20:36:25 +02:00
|
|
|
Templates TemplateSettings `json:"templates" yaml:"Templates"`
|
2019-11-12 04:34:37 +01:00
|
|
|
}
|
2019-11-17 03:08:13 +01:00
|
|
|
|
2020-09-06 14:18:40 +02:00
|
|
|
// NewSettings creates a new Settings instance.
|
2021-12-12 22:09:22 +01:00
|
|
|
func NewSettings(c *Config) *Settings {
|
2020-03-31 18:56:52 +02:00
|
|
|
return &Settings{
|
2020-12-13 14:53:26 +01:00
|
|
|
UI: UISettings{
|
|
|
|
Scrollbar: true,
|
2021-01-04 19:08:44 +01:00
|
|
|
Zoom: false,
|
2021-12-12 22:09:22 +01:00
|
|
|
Theme: c.DefaultTheme(),
|
|
|
|
Language: c.DefaultLocale(),
|
2020-12-13 14:53:26 +01:00
|
|
|
},
|
2022-03-30 20:36:25 +02:00
|
|
|
Search: SearchSettings{
|
|
|
|
BatchSize: 0,
|
|
|
|
PrefetchDist: 0,
|
2020-05-05 18:26:44 +02:00
|
|
|
},
|
2020-03-31 18:56:52 +02:00
|
|
|
Maps: MapsSettings{
|
|
|
|
Animate: 0,
|
2020-03-31 21:03:13 +02:00
|
|
|
Style: "streets",
|
2020-03-31 18:56:52 +02:00
|
|
|
},
|
2020-04-13 18:08:21 +02:00
|
|
|
Features: FeatureSettings{
|
2020-12-30 11:11:58 +01:00
|
|
|
Upload: true,
|
|
|
|
Download: true,
|
|
|
|
Archive: true,
|
|
|
|
Review: true,
|
|
|
|
Private: true,
|
|
|
|
Files: true,
|
2021-02-08 09:04:44 +01:00
|
|
|
Videos: true,
|
2020-12-30 18:10:20 +01:00
|
|
|
Folders: true,
|
2021-01-04 19:08:44 +01:00
|
|
|
Albums: true,
|
2020-12-30 11:11:58 +01:00
|
|
|
Moments: true,
|
|
|
|
Estimates: true,
|
2021-01-04 19:08:44 +01:00
|
|
|
People: true,
|
2020-12-30 11:11:58 +01:00
|
|
|
Labels: true,
|
|
|
|
Places: true,
|
|
|
|
Edit: true,
|
|
|
|
Share: true,
|
|
|
|
Library: true,
|
|
|
|
Import: true,
|
|
|
|
Logs: true,
|
2020-05-04 18:28:23 +02:00
|
|
|
},
|
|
|
|
Import: ImportSettings{
|
2020-12-16 11:59:16 +01:00
|
|
|
Path: entity.RootPath,
|
2020-05-04 18:28:23 +02:00
|
|
|
Move: false,
|
2020-04-12 18:00:31 +02:00
|
|
|
},
|
2020-05-06 15:53:47 +02:00
|
|
|
Index: IndexSettings{
|
2020-12-16 11:59:16 +01:00
|
|
|
Path: entity.RootPath,
|
2020-12-07 16:19:03 +01:00
|
|
|
Rescan: false,
|
|
|
|
Convert: true,
|
|
|
|
},
|
|
|
|
Stack: StackSettings{
|
2020-12-07 17:03:06 +01:00
|
|
|
UUID: true,
|
|
|
|
Meta: true,
|
|
|
|
Name: false,
|
2020-04-14 13:13:45 +02:00
|
|
|
},
|
2020-12-16 11:59:16 +01:00
|
|
|
Share: ShareSettings{
|
|
|
|
Title: "",
|
|
|
|
},
|
|
|
|
Download: DownloadSettings{
|
|
|
|
Name: entity.DownloadNameDefault,
|
|
|
|
},
|
2022-03-30 20:36:25 +02:00
|
|
|
Templates: TemplateSettings{
|
|
|
|
Default: "index.tmpl",
|
|
|
|
},
|
2020-03-31 18:56:52 +02:00
|
|
|
}
|
2019-11-17 03:08:13 +01:00
|
|
|
}
|
|
|
|
|
2020-04-13 18:08:21 +02:00
|
|
|
// Propagate updates settings in other packages as needed.
|
2020-12-07 17:03:06 +01:00
|
|
|
func (s *Settings) Propagate() {
|
2020-12-13 14:53:26 +01:00
|
|
|
i18n.SetLocale(s.UI.Language)
|
2020-04-13 18:08:21 +02:00
|
|
|
}
|
|
|
|
|
2020-12-07 17:03:06 +01:00
|
|
|
// StackSequences tests if files should be stacked based on their file name prefix (sequential names).
|
|
|
|
func (s Settings) StackSequences() bool {
|
2020-12-11 17:21:13 +01:00
|
|
|
return s.Stack.Name
|
2020-12-07 17:03:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// StackUUID tests if files should be stacked based on unique image or instance id.
|
|
|
|
func (s Settings) StackUUID() bool {
|
2020-12-11 17:21:13 +01:00
|
|
|
return s.Stack.UUID
|
2020-12-07 17:03:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// StackMeta tests if files should be stacked based on their place and time metadata.
|
|
|
|
func (s Settings) StackMeta() bool {
|
2020-12-11 17:21:13 +01:00
|
|
|
return s.Stack.Meta
|
2020-12-07 17:03:06 +01:00
|
|
|
}
|
|
|
|
|
2020-09-06 14:18:40 +02:00
|
|
|
// Load user settings from file.
|
2020-03-28 21:44:30 +01:00
|
|
|
func (s *Settings) Load(fileName string) error {
|
2020-01-12 14:00:56 +01:00
|
|
|
if !fs.FileExists(fileName) {
|
2021-12-14 20:01:39 +01:00
|
|
|
return fmt.Errorf("settings file not found: %s", sanitize.Log(fileName))
|
2019-11-17 03:08:13 +01:00
|
|
|
}
|
|
|
|
|
2021-10-06 07:10:50 +02:00
|
|
|
yamlConfig, err := os.ReadFile(fileName)
|
2019-11-17 03:08:13 +01:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-04-13 18:08:21 +02:00
|
|
|
if err := yaml.Unmarshal(yamlConfig, s); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
s.Propagate()
|
|
|
|
|
|
|
|
return nil
|
2019-11-17 03:08:13 +01:00
|
|
|
}
|
|
|
|
|
2020-09-06 14:18:40 +02:00
|
|
|
// Save user settings to a file.
|
2020-03-28 21:44:30 +01:00
|
|
|
func (s *Settings) Save(fileName string) error {
|
2019-11-17 03:08:13 +01:00
|
|
|
data, err := yaml.Marshal(s)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2020-04-13 18:08:21 +02:00
|
|
|
s.Propagate()
|
|
|
|
|
2021-10-06 07:10:50 +02:00
|
|
|
if err := os.WriteFile(fileName, data, os.ModePerm); err != nil {
|
2020-04-13 18:08:21 +02:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
2019-11-17 03:08:13 +01:00
|
|
|
}
|
2020-01-02 00:03:07 +01:00
|
|
|
|
2020-04-13 18:08:21 +02:00
|
|
|
// initSettings initializes user settings from a config file.
|
|
|
|
func (c *Config) initSettings() {
|
2022-03-28 16:13:41 +02:00
|
|
|
if c.settings != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-12-12 22:09:22 +01:00
|
|
|
c.settings = NewSettings(c)
|
2020-12-04 12:15:59 +01:00
|
|
|
fileName := c.SettingsFile()
|
|
|
|
|
|
|
|
if err := c.settings.Load(fileName); err == nil {
|
2020-12-26 18:30:04 +01:00
|
|
|
log.Debugf("config: settings loaded from %s ", fileName)
|
2020-12-04 12:15:59 +01:00
|
|
|
} else if err := c.settings.Save(fileName); err != nil {
|
|
|
|
log.Errorf("failed creating %s: %s", fileName, err)
|
|
|
|
} else {
|
|
|
|
log.Debugf("config: created %s ", fileName)
|
2020-01-02 00:03:07 +01:00
|
|
|
}
|
|
|
|
|
2020-07-15 01:26:54 +02:00
|
|
|
i18n.SetDir(c.LocalesPath())
|
|
|
|
|
2020-04-13 18:08:21 +02:00
|
|
|
c.settings.Propagate()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Settings returns the current user settings.
|
|
|
|
func (c *Config) Settings() *Settings {
|
2022-03-28 16:13:41 +02:00
|
|
|
c.initSettings()
|
2020-10-08 08:52:03 +02:00
|
|
|
|
2020-12-18 09:11:42 +01:00
|
|
|
if c.DisablePlaces() {
|
|
|
|
c.settings.Features.Places = false
|
|
|
|
}
|
|
|
|
|
2020-04-13 18:08:21 +02:00
|
|
|
return c.settings
|
2020-01-02 00:03:07 +01:00
|
|
|
}
|