mirror of
https://github.com/photoprism/photoprism.git
synced 2025-10-28 19:12:03 +08:00
Backend: Refactor package structure
Signed-off-by: Michael Mayer <michael@liquidbytes.net>
This commit is contained in:
@@ -13,24 +13,11 @@ import (
|
|||||||
"github.com/photoprism/photoprism/internal/event"
|
"github.com/photoprism/photoprism/internal/event"
|
||||||
"github.com/photoprism/photoprism/internal/form"
|
"github.com/photoprism/photoprism/internal/form"
|
||||||
"github.com/photoprism/photoprism/internal/photoprism"
|
"github.com/photoprism/photoprism/internal/photoprism"
|
||||||
|
"github.com/photoprism/photoprism/internal/service"
|
||||||
"github.com/photoprism/photoprism/pkg/fs"
|
"github.com/photoprism/photoprism/pkg/fs"
|
||||||
"github.com/photoprism/photoprism/pkg/txt"
|
"github.com/photoprism/photoprism/pkg/txt"
|
||||||
)
|
)
|
||||||
|
|
||||||
var imp *photoprism.Import
|
|
||||||
|
|
||||||
func initImport(conf *config.Config) {
|
|
||||||
if imp != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
initIndex(conf)
|
|
||||||
|
|
||||||
convert := photoprism.NewConvert(conf)
|
|
||||||
|
|
||||||
imp = photoprism.NewImport(conf, ind, convert)
|
|
||||||
}
|
|
||||||
|
|
||||||
// POST /api/v1/import*
|
// POST /api/v1/import*
|
||||||
func StartImport(router *gin.RouterGroup, conf *config.Config) {
|
func StartImport(router *gin.RouterGroup, conf *config.Config) {
|
||||||
router.POST("/import/*path", func(c *gin.Context) {
|
router.POST("/import/*path", func(c *gin.Context) {
|
||||||
@@ -64,7 +51,7 @@ func StartImport(router *gin.RouterGroup, conf *config.Config) {
|
|||||||
|
|
||||||
path = filepath.Clean(path)
|
path = filepath.Clean(path)
|
||||||
|
|
||||||
initImport(conf)
|
imp := service.Import()
|
||||||
|
|
||||||
var opt photoprism.ImportOptions
|
var opt photoprism.ImportOptions
|
||||||
|
|
||||||
@@ -105,7 +92,7 @@ func CancelImport(router *gin.RouterGroup, conf *config.Config) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
initImport(conf)
|
imp := service.Import()
|
||||||
|
|
||||||
imp.Cancel()
|
imp.Cancel()
|
||||||
|
|
||||||
|
|||||||
@@ -7,38 +7,14 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/photoprism/photoprism/internal/classify"
|
|
||||||
"github.com/photoprism/photoprism/internal/config"
|
"github.com/photoprism/photoprism/internal/config"
|
||||||
"github.com/photoprism/photoprism/internal/event"
|
"github.com/photoprism/photoprism/internal/event"
|
||||||
"github.com/photoprism/photoprism/internal/form"
|
"github.com/photoprism/photoprism/internal/form"
|
||||||
"github.com/photoprism/photoprism/internal/nsfw"
|
|
||||||
"github.com/photoprism/photoprism/internal/photoprism"
|
"github.com/photoprism/photoprism/internal/photoprism"
|
||||||
|
"github.com/photoprism/photoprism/internal/service"
|
||||||
"github.com/photoprism/photoprism/pkg/txt"
|
"github.com/photoprism/photoprism/pkg/txt"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ind *photoprism.Index
|
|
||||||
var nd *nsfw.Detector
|
|
||||||
|
|
||||||
func initIndex(conf *config.Config) {
|
|
||||||
if ind != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
initNsfwDetector(conf)
|
|
||||||
|
|
||||||
tf := classify.New(conf.ResourcesPath(), conf.TensorFlowDisabled())
|
|
||||||
|
|
||||||
ind = photoprism.NewIndex(conf, tf, nd)
|
|
||||||
}
|
|
||||||
|
|
||||||
func initNsfwDetector(conf *config.Config) {
|
|
||||||
if nd != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
nd = nsfw.New(conf.NSFWModelPath())
|
|
||||||
}
|
|
||||||
|
|
||||||
// POST /api/v1/index
|
// POST /api/v1/index
|
||||||
func StartIndexing(router *gin.RouterGroup, conf *config.Config) {
|
func StartIndexing(router *gin.RouterGroup, conf *config.Config) {
|
||||||
router.POST("/index", func(c *gin.Context) {
|
router.POST("/index", func(c *gin.Context) {
|
||||||
@@ -67,7 +43,7 @@ func StartIndexing(router *gin.RouterGroup, conf *config.Config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if f.ConvertRaw && !conf.ReadOnly() {
|
if f.ConvertRaw && !conf.ReadOnly() {
|
||||||
convert := photoprism.NewConvert(conf)
|
convert := service.Convert()
|
||||||
|
|
||||||
if err := convert.Start(conf.OriginalsPath()); err != nil {
|
if err := convert.Start(conf.OriginalsPath()); err != nil {
|
||||||
cancel(err)
|
cancel(err)
|
||||||
@@ -76,7 +52,7 @@ func StartIndexing(router *gin.RouterGroup, conf *config.Config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if f.CreateThumbs {
|
if f.CreateThumbs {
|
||||||
rs := photoprism.NewResample(conf)
|
rs := service.Resample()
|
||||||
|
|
||||||
if err := rs.Start(false); err != nil {
|
if err := rs.Start(false); err != nil {
|
||||||
cancel(err)
|
cancel(err)
|
||||||
@@ -84,7 +60,7 @@ func StartIndexing(router *gin.RouterGroup, conf *config.Config) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
initIndex(conf)
|
ind := service.Index()
|
||||||
|
|
||||||
if f.SkipUnchanged {
|
if f.SkipUnchanged {
|
||||||
ind.Start(photoprism.IndexOptionsNone())
|
ind.Start(photoprism.IndexOptionsNone())
|
||||||
@@ -110,7 +86,7 @@ func CancelIndexing(router *gin.RouterGroup, conf *config.Config) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
initIndex(conf)
|
ind := service.Index()
|
||||||
|
|
||||||
ind.Cancel()
|
ind.Cancel()
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import (
|
|||||||
|
|
||||||
"github.com/photoprism/photoprism/internal/config"
|
"github.com/photoprism/photoprism/internal/config"
|
||||||
"github.com/photoprism/photoprism/internal/event"
|
"github.com/photoprism/photoprism/internal/event"
|
||||||
|
"github.com/photoprism/photoprism/internal/service"
|
||||||
"github.com/photoprism/photoprism/pkg/txt"
|
"github.com/photoprism/photoprism/pkg/txt"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@@ -65,7 +66,7 @@ func Upload(router *gin.RouterGroup, conf *config.Config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !conf.UploadNSFW() {
|
if !conf.UploadNSFW() {
|
||||||
initNsfwDetector(conf)
|
nd := service.NsfwDetector()
|
||||||
|
|
||||||
containsNSFW := false
|
containsNSFW := false
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/photoprism/photoprism/internal/config"
|
"github.com/photoprism/photoprism/internal/config"
|
||||||
"github.com/photoprism/photoprism/internal/photoprism"
|
"github.com/photoprism/photoprism/internal/service"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -20,6 +20,7 @@ func convertAction(ctx *cli.Context) error {
|
|||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
conf := config.NewConfig(ctx)
|
conf := config.NewConfig(ctx)
|
||||||
|
service.SetConfig(conf)
|
||||||
|
|
||||||
if conf.ReadOnly() {
|
if conf.ReadOnly() {
|
||||||
return config.ErrReadOnly
|
return config.ErrReadOnly
|
||||||
@@ -31,9 +32,11 @@ func convertAction(ctx *cli.Context) error {
|
|||||||
|
|
||||||
log.Infof("converting RAW images in %s to JPEG", conf.OriginalsPath())
|
log.Infof("converting RAW images in %s to JPEG", conf.OriginalsPath())
|
||||||
|
|
||||||
convert := photoprism.NewConvert(conf)
|
convert := service.Convert()
|
||||||
|
|
||||||
convert.Start(conf.OriginalsPath())
|
if err := convert.Start(conf.OriginalsPath()); err != nil {
|
||||||
|
log.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
elapsed := time.Since(start)
|
elapsed := time.Since(start)
|
||||||
|
|
||||||
|
|||||||
@@ -7,10 +7,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/photoprism/photoprism/internal/classify"
|
|
||||||
"github.com/photoprism/photoprism/internal/config"
|
"github.com/photoprism/photoprism/internal/config"
|
||||||
"github.com/photoprism/photoprism/internal/nsfw"
|
|
||||||
"github.com/photoprism/photoprism/internal/photoprism"
|
"github.com/photoprism/photoprism/internal/photoprism"
|
||||||
|
"github.com/photoprism/photoprism/internal/service"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -27,6 +26,7 @@ func copyAction(ctx *cli.Context) error {
|
|||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
conf := config.NewConfig(ctx)
|
conf := config.NewConfig(ctx)
|
||||||
|
service.SetConfig(conf)
|
||||||
|
|
||||||
// very if copy directory exist and is writable
|
// very if copy directory exist and is writable
|
||||||
if conf.ReadOnly() {
|
if conf.ReadOnly() {
|
||||||
@@ -66,14 +66,7 @@ func copyAction(ctx *cli.Context) error {
|
|||||||
|
|
||||||
log.Infof("copying media files from %s to %s", sourcePath, conf.OriginalsPath())
|
log.Infof("copying media files from %s to %s", sourcePath, conf.OriginalsPath())
|
||||||
|
|
||||||
tensorFlow := classify.New(conf.ResourcesPath(), conf.TensorFlowDisabled())
|
imp := service.Import()
|
||||||
nsfwDetector := nsfw.New(conf.NSFWModelPath())
|
|
||||||
|
|
||||||
ind := photoprism.NewIndex(conf, tensorFlow, nsfwDetector)
|
|
||||||
|
|
||||||
convert := photoprism.NewConvert(conf)
|
|
||||||
|
|
||||||
imp := photoprism.NewImport(conf, ind, convert)
|
|
||||||
opt := photoprism.ImportOptionsCopy(sourcePath)
|
opt := photoprism.ImportOptionsCopy(sourcePath)
|
||||||
|
|
||||||
imp.Start(opt)
|
imp.Start(opt)
|
||||||
|
|||||||
@@ -7,10 +7,9 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/photoprism/photoprism/internal/classify"
|
|
||||||
"github.com/photoprism/photoprism/internal/config"
|
"github.com/photoprism/photoprism/internal/config"
|
||||||
"github.com/photoprism/photoprism/internal/nsfw"
|
|
||||||
"github.com/photoprism/photoprism/internal/photoprism"
|
"github.com/photoprism/photoprism/internal/photoprism"
|
||||||
|
"github.com/photoprism/photoprism/internal/service"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -27,6 +26,7 @@ func importAction(ctx *cli.Context) error {
|
|||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
conf := config.NewConfig(ctx)
|
conf := config.NewConfig(ctx)
|
||||||
|
service.SetConfig(conf)
|
||||||
|
|
||||||
// very if copy directory exist and is writable
|
// very if copy directory exist and is writable
|
||||||
if conf.ReadOnly() {
|
if conf.ReadOnly() {
|
||||||
@@ -66,14 +66,7 @@ func importAction(ctx *cli.Context) error {
|
|||||||
|
|
||||||
log.Infof("moving media files from %s to %s", sourcePath, conf.OriginalsPath())
|
log.Infof("moving media files from %s to %s", sourcePath, conf.OriginalsPath())
|
||||||
|
|
||||||
tensorFlow := classify.New(conf.ResourcesPath(), conf.TensorFlowDisabled())
|
imp := service.Import()
|
||||||
nsfwDetector := nsfw.New(conf.NSFWModelPath())
|
|
||||||
|
|
||||||
ind := photoprism.NewIndex(conf, tensorFlow, nsfwDetector)
|
|
||||||
|
|
||||||
convert := photoprism.NewConvert(conf)
|
|
||||||
|
|
||||||
imp := photoprism.NewImport(conf, ind, convert)
|
|
||||||
opt := photoprism.ImportOptionsMove(sourcePath)
|
opt := photoprism.ImportOptionsMove(sourcePath)
|
||||||
|
|
||||||
imp.Start(opt)
|
imp.Start(opt)
|
||||||
|
|||||||
@@ -4,10 +4,9 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/photoprism/photoprism/internal/classify"
|
|
||||||
"github.com/photoprism/photoprism/internal/config"
|
"github.com/photoprism/photoprism/internal/config"
|
||||||
"github.com/photoprism/photoprism/internal/nsfw"
|
|
||||||
"github.com/photoprism/photoprism/internal/photoprism"
|
"github.com/photoprism/photoprism/internal/photoprism"
|
||||||
|
"github.com/photoprism/photoprism/internal/service"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -31,6 +30,7 @@ func indexAction(ctx *cli.Context) error {
|
|||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
conf := config.NewConfig(ctx)
|
conf := config.NewConfig(ctx)
|
||||||
|
service.SetConfig(conf)
|
||||||
|
|
||||||
if err := conf.CreateDirectories(); err != nil {
|
if err := conf.CreateDirectories(); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -49,9 +49,7 @@ func indexAction(ctx *cli.Context) error {
|
|||||||
log.Infof("read-only mode enabled")
|
log.Infof("read-only mode enabled")
|
||||||
}
|
}
|
||||||
|
|
||||||
tf := classify.New(conf.ResourcesPath(), conf.TensorFlowDisabled())
|
ind := service.Index()
|
||||||
nd := nsfw.New(conf.NSFWModelPath())
|
|
||||||
ind := photoprism.NewIndex(conf, tf, nd)
|
|
||||||
|
|
||||||
var opt photoprism.IndexOptions
|
var opt photoprism.IndexOptions
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
"github.com/photoprism/photoprism/internal/config"
|
"github.com/photoprism/photoprism/internal/config"
|
||||||
"github.com/photoprism/photoprism/internal/photoprism"
|
"github.com/photoprism/photoprism/internal/photoprism"
|
||||||
"github.com/photoprism/photoprism/internal/server"
|
"github.com/photoprism/photoprism/internal/server"
|
||||||
|
"github.com/photoprism/photoprism/internal/service"
|
||||||
"github.com/photoprism/photoprism/pkg/fs"
|
"github.com/photoprism/photoprism/pkg/fs"
|
||||||
"github.com/sevlyar/go-daemon"
|
"github.com/sevlyar/go-daemon"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
@@ -41,6 +42,7 @@ var startFlags = []cli.Flag{
|
|||||||
// startAction start the web server and initializes the daemon
|
// startAction start the web server and initializes the daemon
|
||||||
func startAction(ctx *cli.Context) error {
|
func startAction(ctx *cli.Context) error {
|
||||||
conf := config.NewConfig(ctx)
|
conf := config.NewConfig(ctx)
|
||||||
|
service.SetConfig(conf)
|
||||||
|
|
||||||
if err := conf.CreateDirectories(); err != nil {
|
if err := conf.CreateDirectories(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/photoprism/photoprism/internal/config"
|
"github.com/photoprism/photoprism/internal/config"
|
||||||
"github.com/photoprism/photoprism/internal/photoprism"
|
"github.com/photoprism/photoprism/internal/service"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -26,6 +26,7 @@ func thumbsAction(ctx *cli.Context) error {
|
|||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
conf := config.NewConfig(ctx)
|
conf := config.NewConfig(ctx)
|
||||||
|
service.SetConfig(conf)
|
||||||
|
|
||||||
if err := conf.CreateDirectories(); err != nil {
|
if err := conf.CreateDirectories(); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -33,7 +34,7 @@ func thumbsAction(ctx *cli.Context) error {
|
|||||||
|
|
||||||
log.Infof("creating thumbnails in \"%s\"", conf.ThumbnailsPath())
|
log.Infof("creating thumbnails in \"%s\"", conf.ThumbnailsPath())
|
||||||
|
|
||||||
rs := photoprism.NewResample(conf)
|
rs := service.Resample()
|
||||||
|
|
||||||
if err := rs.Start(ctx.Bool("force")); err != nil {
|
if err := rs.Start(ctx.Bool("force")); err != nil {
|
||||||
log.Error(err)
|
log.Error(err)
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import (
|
|||||||
|
|
||||||
"github.com/jinzhu/gorm"
|
"github.com/jinzhu/gorm"
|
||||||
"github.com/photoprism/photoprism/internal/form"
|
"github.com/photoprism/photoprism/internal/form"
|
||||||
"github.com/photoprism/photoprism/internal/service"
|
"github.com/photoprism/photoprism/internal/remote"
|
||||||
"github.com/photoprism/photoprism/internal/service/webdav"
|
"github.com/photoprism/photoprism/internal/remote/webdav"
|
||||||
"github.com/photoprism/photoprism/pkg/fs"
|
"github.com/photoprism/photoprism/pkg/fs"
|
||||||
"github.com/ulule/deepcopier"
|
"github.com/ulule/deepcopier"
|
||||||
)
|
)
|
||||||
@@ -73,7 +73,7 @@ func (m *Account) Save(form form.Account, db *gorm.DB) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if m.AccType != string(service.TypeWebDAV) {
|
if m.AccType != string(remote.ServiceWebDAV) {
|
||||||
// TODO: Only WebDAV supported at the moment
|
// TODO: Only WebDAV supported at the moment
|
||||||
m.AccShare = false
|
m.AccShare = false
|
||||||
m.AccSync = false
|
m.AccSync = false
|
||||||
@@ -97,7 +97,7 @@ func (m *Account) Delete(db *gorm.DB) error {
|
|||||||
|
|
||||||
// Directories returns a list of directories or albums in an account.
|
// Directories returns a list of directories or albums in an account.
|
||||||
func (m *Account) Directories() (result fs.FileInfos, err error) {
|
func (m *Account) Directories() (result fs.FileInfos, err error) {
|
||||||
if m.AccType == service.TypeWebDAV {
|
if m.AccType == remote.ServiceWebDAV {
|
||||||
c := webdav.New(m.AccURL, m.AccUser, m.AccPass)
|
c := webdav.New(m.AccURL, m.AccUser, m.AccPass)
|
||||||
result, err = c.Directories("/", true)
|
result, err = c.Directories("/", true)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package form
|
package form
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/photoprism/photoprism/internal/service"
|
"github.com/photoprism/photoprism/internal/remote"
|
||||||
"github.com/ulule/deepcopier"
|
"github.com/ulule/deepcopier"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ func NewAccount(m interface{}) (f Account, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *Account) ServiceDiscovery() error {
|
func (f *Account) ServiceDiscovery() error {
|
||||||
acc, err := service.Discover(f.AccURL, f.AccUser, f.AccPass)
|
acc, err := remote.Discover(f.AccURL, f.AccUser, f.AccPass)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ import (
|
|||||||
"github.com/photoprism/photoprism/internal/form"
|
"github.com/photoprism/photoprism/internal/form"
|
||||||
"github.com/photoprism/photoprism/internal/mutex"
|
"github.com/photoprism/photoprism/internal/mutex"
|
||||||
"github.com/photoprism/photoprism/internal/query"
|
"github.com/photoprism/photoprism/internal/query"
|
||||||
"github.com/photoprism/photoprism/internal/service"
|
"github.com/photoprism/photoprism/internal/remote"
|
||||||
"github.com/photoprism/photoprism/internal/service/webdav"
|
"github.com/photoprism/photoprism/internal/remote/webdav"
|
||||||
"github.com/photoprism/photoprism/internal/thumb"
|
"github.com/photoprism/photoprism/internal/thumb"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ func (s *Share) Start() (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if a.AccType != service.TypeWebDAV {
|
if a.AccType != remote.ServiceWebDAV {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,7 +129,7 @@ func (s *Share) Start() (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if a.AccType != service.TypeWebDAV {
|
if a.AccType != remote.ServiceWebDAV {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import (
|
|||||||
"github.com/photoprism/photoprism/internal/form"
|
"github.com/photoprism/photoprism/internal/form"
|
||||||
"github.com/photoprism/photoprism/internal/mutex"
|
"github.com/photoprism/photoprism/internal/mutex"
|
||||||
"github.com/photoprism/photoprism/internal/query"
|
"github.com/photoprism/photoprism/internal/query"
|
||||||
"github.com/photoprism/photoprism/internal/service"
|
"github.com/photoprism/photoprism/internal/remote"
|
||||||
"github.com/photoprism/photoprism/internal/service/webdav"
|
"github.com/photoprism/photoprism/internal/remote/webdav"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Sync represents a sync worker.
|
// Sync represents a sync worker.
|
||||||
@@ -43,7 +43,7 @@ func (s *Sync) Start() (err error) {
|
|||||||
accounts, err := q.Accounts(f)
|
accounts, err := q.Accounts(f)
|
||||||
|
|
||||||
for _, a := range accounts {
|
for _, a := range accounts {
|
||||||
if a.AccType != service.TypeWebDAV {
|
if a.AccType != remote.ServiceWebDAV {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,7 +112,7 @@ func (s *Sync) Start() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Sync) getRemoteFiles(a entity.Account) (complete bool, err error) {
|
func (s *Sync) getRemoteFiles(a entity.Account) (complete bool, err error) {
|
||||||
if a.AccType != service.TypeWebDAV {
|
if a.AccType != remote.ServiceWebDAV {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,5 +221,6 @@ func (s *Sync) download(a entity.Account) (complete bool, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Sync) upload(a entity.Account) (complete bool, err error) {
|
func (s *Sync) upload(a entity.Account) (complete bool, err error) {
|
||||||
|
// TODO: Not implemented yet
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|||||||
176
internal/remote/service.go
Normal file
176
internal/remote/service.go
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
/*
|
||||||
|
Package service implements a remote service abstraction.
|
||||||
|
|
||||||
|
Additional information can be found in our Developer Guide:
|
||||||
|
|
||||||
|
https://github.com/photoprism/photoprism/wiki
|
||||||
|
*/
|
||||||
|
package remote
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/photoprism/photoprism/pkg/txt"
|
||||||
|
)
|
||||||
|
|
||||||
|
var client = &http.Client{}
|
||||||
|
|
||||||
|
const (
|
||||||
|
ServiceWeb = "web"
|
||||||
|
ServiceWebDAV = "webdav"
|
||||||
|
ServiceFacebook = "facebook"
|
||||||
|
ServiceTwitter = "twitter"
|
||||||
|
ServiceFlickr = "flickr"
|
||||||
|
ServiceInstagram = "instagram"
|
||||||
|
ServiceEyeEm = "eyeem"
|
||||||
|
ServiceTelegram = "telegram"
|
||||||
|
ServiceWhatsApp = "whatsapp"
|
||||||
|
ServiceGPhotos = "gphotos"
|
||||||
|
ServiceGDrive = "gdrive"
|
||||||
|
ServiceOneDrive = "onedrive"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Account struct {
|
||||||
|
AccName string
|
||||||
|
AccURL string
|
||||||
|
AccType string
|
||||||
|
AccKey string
|
||||||
|
AccUser string
|
||||||
|
AccPass string
|
||||||
|
}
|
||||||
|
|
||||||
|
type Heuristic struct {
|
||||||
|
ServiceType string
|
||||||
|
Domains []string
|
||||||
|
Paths []string
|
||||||
|
Method string
|
||||||
|
}
|
||||||
|
|
||||||
|
var Heuristics = []Heuristic{
|
||||||
|
{ServiceFacebook, []string{"facebook.com", "www.facebook.com"}, []string{}, "GET"},
|
||||||
|
{ServiceTwitter, []string{"twitter.com"}, []string{}, "GET"},
|
||||||
|
{ServiceFlickr, []string{"flickr.com", "www.flickr.com"}, []string{}, "GET"},
|
||||||
|
{ServiceInstagram, []string{"instagram.com", "www.instagram.com"}, []string{}, "GET"},
|
||||||
|
{ServiceEyeEm, []string{"eyeem.com", "www.eyeem.com"}, []string{}, "GET"},
|
||||||
|
{ServiceTelegram, []string{"web.telegram.org", "www.telegram.org", "telegram.org"}, []string{}, "GET"},
|
||||||
|
{ServiceWhatsApp, []string{"web.whatsapp.com", "www.whatsapp.com", "whatsapp.com"}, []string{}, "GET"},
|
||||||
|
{ServiceOneDrive, []string{"onedrive.live.com"}, []string{}, "GET"},
|
||||||
|
{ServiceGDrive, []string{"drive.google.com"}, []string{}, "GET"},
|
||||||
|
{ServiceGPhotos, []string{"photos.google.com"}, []string{}, "GET"},
|
||||||
|
{ServiceWebDAV, []string{}, []string{"/", "/webdav", "/remote.php/dav/files/{user}", "/remote.php/webdav", "/dav/files/{user}", "/servlet/webdav.infostore/"}, "PROPFIND"},
|
||||||
|
{ServiceWeb, []string{}, []string{}, "GET"},
|
||||||
|
}
|
||||||
|
|
||||||
|
func HttpOk(method, rawUrl string) bool {
|
||||||
|
req, err := http.NewRequest(method, rawUrl, nil)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp, err := client.Do(req); err != nil {
|
||||||
|
return false
|
||||||
|
} else if resp.StatusCode < 400 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h Heuristic) MatchDomain(match string) bool {
|
||||||
|
if len(h.Domains) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, m := range h.Domains {
|
||||||
|
if m == match {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h Heuristic) Discover(rawUrl, user string) *url.URL {
|
||||||
|
u, err := url.Parse(rawUrl)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if HttpOk(h.Method, u.String()) {
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, p := range h.Paths {
|
||||||
|
strings.Replace(p, "{user}", user, -1)
|
||||||
|
u.Path = p
|
||||||
|
|
||||||
|
if HttpOk(h.Method, u.String()) {
|
||||||
|
return u
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Discover(rawUrl, user, pass string) (result Account, err error) {
|
||||||
|
if rawUrl == "" {
|
||||||
|
return result, errors.New("service URL is empty")
|
||||||
|
}
|
||||||
|
|
||||||
|
u, err := url.Parse(rawUrl)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
u.Host = strings.ToLower(u.Host)
|
||||||
|
|
||||||
|
result.AccUser = u.User.Username()
|
||||||
|
result.AccPass, _ = u.User.Password()
|
||||||
|
|
||||||
|
// Extract user info
|
||||||
|
if user != "" {
|
||||||
|
result.AccUser = user
|
||||||
|
}
|
||||||
|
|
||||||
|
if pass != "" {
|
||||||
|
result.AccPass = pass
|
||||||
|
}
|
||||||
|
|
||||||
|
if user != "" || pass != "" {
|
||||||
|
u.User = url.UserPassword(result.AccUser, result.AccPass)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set default scheme
|
||||||
|
if u.Scheme == "" {
|
||||||
|
u.Scheme = "https"
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, h := range Heuristics {
|
||||||
|
if !h.MatchDomain(u.Host) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if serviceUrl := h.Discover(u.String(), result.AccUser); serviceUrl != nil {
|
||||||
|
serviceUrl.User = nil
|
||||||
|
|
||||||
|
if w := txt.Keywords(serviceUrl.Host); len(w) > 0 {
|
||||||
|
result.AccName = strings.Title(w[0])
|
||||||
|
} else {
|
||||||
|
result.AccName = serviceUrl.Host
|
||||||
|
}
|
||||||
|
|
||||||
|
result.AccType = h.ServiceType
|
||||||
|
result.AccURL = serviceUrl.String()
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, errors.New("could not connect")
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package service
|
package remote
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
19
internal/service/classify.go
Normal file
19
internal/service/classify.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/photoprism/photoprism/internal/classify"
|
||||||
|
)
|
||||||
|
|
||||||
|
var onceClassify sync.Once
|
||||||
|
|
||||||
|
func initClassify() {
|
||||||
|
services.Classify = classify.New(Config().ResourcesPath(), Config().TensorFlowDisabled())
|
||||||
|
}
|
||||||
|
|
||||||
|
func Classify() *classify.TensorFlow {
|
||||||
|
onceClassify.Do(initClassify)
|
||||||
|
|
||||||
|
return services.Classify
|
||||||
|
}
|
||||||
19
internal/service/convert.go
Normal file
19
internal/service/convert.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/photoprism/photoprism/internal/photoprism"
|
||||||
|
)
|
||||||
|
|
||||||
|
var onceConvert sync.Once
|
||||||
|
|
||||||
|
func initConvert() {
|
||||||
|
services.Convert = photoprism.NewConvert(Config())
|
||||||
|
}
|
||||||
|
|
||||||
|
func Convert() *photoprism.Convert {
|
||||||
|
onceConvert.Do(initConvert)
|
||||||
|
|
||||||
|
return services.Convert
|
||||||
|
}
|
||||||
19
internal/service/import.go
Normal file
19
internal/service/import.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/photoprism/photoprism/internal/photoprism"
|
||||||
|
)
|
||||||
|
|
||||||
|
var onceImport sync.Once
|
||||||
|
|
||||||
|
func initImport() {
|
||||||
|
services.Import = photoprism.NewImport(Config(), Index(), Convert())
|
||||||
|
}
|
||||||
|
|
||||||
|
func Import() *photoprism.Import {
|
||||||
|
onceImport.Do(initImport)
|
||||||
|
|
||||||
|
return services.Import
|
||||||
|
}
|
||||||
19
internal/service/index.go
Normal file
19
internal/service/index.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/photoprism/photoprism/internal/photoprism"
|
||||||
|
)
|
||||||
|
|
||||||
|
var onceIndex sync.Once
|
||||||
|
|
||||||
|
func initIndex() {
|
||||||
|
services.Index = photoprism.NewIndex(Config(), Classify(), NsfwDetector())
|
||||||
|
}
|
||||||
|
|
||||||
|
func Index() *photoprism.Index {
|
||||||
|
onceIndex.Do(initIndex)
|
||||||
|
|
||||||
|
return services.Index
|
||||||
|
}
|
||||||
19
internal/service/nsfw.go
Normal file
19
internal/service/nsfw.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/photoprism/photoprism/internal/nsfw"
|
||||||
|
)
|
||||||
|
|
||||||
|
var onceNsfwDetector sync.Once
|
||||||
|
|
||||||
|
func initNsfwDetector() {
|
||||||
|
services.Nsfw = nsfw.New(conf.NSFWModelPath())
|
||||||
|
}
|
||||||
|
|
||||||
|
func NsfwDetector() *nsfw.Detector {
|
||||||
|
onceNsfwDetector.Do(initNsfwDetector)
|
||||||
|
|
||||||
|
return services.Nsfw
|
||||||
|
}
|
||||||
19
internal/service/resample.go
Normal file
19
internal/service/resample.go
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/photoprism/photoprism/internal/photoprism"
|
||||||
|
)
|
||||||
|
|
||||||
|
var onceResample sync.Once
|
||||||
|
|
||||||
|
func initResample() {
|
||||||
|
services.Resample = photoprism.NewResample(Config())
|
||||||
|
}
|
||||||
|
|
||||||
|
func Resample() *photoprism.Resample {
|
||||||
|
onceResample.Do(initResample)
|
||||||
|
|
||||||
|
return services.Resample
|
||||||
|
}
|
||||||
@@ -1,178 +1,35 @@
|
|||||||
/*
|
|
||||||
Package service implements a remote service abstraction.
|
|
||||||
|
|
||||||
Additional information can be found in our Developer Guide:
|
|
||||||
|
|
||||||
https://github.com/photoprism/photoprism/wiki
|
|
||||||
*/
|
|
||||||
package service
|
package service
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"github.com/photoprism/photoprism/internal/classify"
|
||||||
"net/http"
|
"github.com/photoprism/photoprism/internal/config"
|
||||||
"net/url"
|
"github.com/photoprism/photoprism/internal/nsfw"
|
||||||
"strings"
|
"github.com/photoprism/photoprism/internal/photoprism"
|
||||||
|
|
||||||
"github.com/photoprism/photoprism/internal/event"
|
|
||||||
"github.com/photoprism/photoprism/pkg/txt"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var log = event.Log
|
var conf *config.Config
|
||||||
var client = &http.Client{}
|
|
||||||
|
|
||||||
const (
|
var services struct {
|
||||||
TypeWeb = "web"
|
Import *photoprism.Import
|
||||||
TypeWebDAV = "webdav"
|
Index *photoprism.Index
|
||||||
TypeFacebook = "facebook"
|
Nsfw *nsfw.Detector
|
||||||
TypeTwitter = "twitter"
|
Convert *photoprism.Convert
|
||||||
TypeFlickr = "flickr"
|
Resample *photoprism.Resample
|
||||||
TypeInstagram = "instagram"
|
Classify *classify.TensorFlow
|
||||||
TypeEyeEm = "eyeem"
|
|
||||||
TypeTelegram = "telegram"
|
|
||||||
TypeWhatsApp = "whatsapp"
|
|
||||||
TypeGooglePhotos = "gphotos"
|
|
||||||
TypeGoogleDrive = "gdrive"
|
|
||||||
TypeOneDrive = "onedrive"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Account struct {
|
|
||||||
AccName string
|
|
||||||
AccURL string
|
|
||||||
AccType string
|
|
||||||
AccKey string
|
|
||||||
AccUser string
|
|
||||||
AccPass string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type Heuristic struct {
|
func SetConfig(c *config.Config) {
|
||||||
ServiceType string
|
if c == nil {
|
||||||
Domains []string
|
panic("config is nil")
|
||||||
Paths []string
|
}
|
||||||
Method string
|
|
||||||
|
conf = c
|
||||||
}
|
}
|
||||||
|
|
||||||
var Heuristics = []Heuristic{
|
func Config() *config.Config {
|
||||||
{TypeFacebook, []string{"facebook.com", "www.facebook.com"}, []string{}, "GET"},
|
if conf == nil {
|
||||||
{TypeTwitter, []string{"twitter.com"}, []string{}, "GET"},
|
panic("config is nil")
|
||||||
{TypeFlickr, []string{"flickr.com", "www.flickr.com"}, []string{}, "GET"},
|
}
|
||||||
{TypeInstagram, []string{"instagram.com", "www.instagram.com"}, []string{}, "GET"},
|
|
||||||
{TypeEyeEm, []string{"eyeem.com", "www.eyeem.com"}, []string{}, "GET"},
|
return conf
|
||||||
{TypeTelegram, []string{"web.telegram.org", "www.telegram.org", "telegram.org"}, []string{}, "GET"},
|
|
||||||
{TypeWhatsApp, []string{"web.whatsapp.com", "www.whatsapp.com", "whatsapp.com"}, []string{}, "GET"},
|
|
||||||
{TypeOneDrive, []string{"onedrive.live.com"}, []string{}, "GET"},
|
|
||||||
{TypeGoogleDrive, []string{"drive.google.com"}, []string{}, "GET"},
|
|
||||||
{TypeGooglePhotos, []string{"photos.google.com"}, []string{}, "GET"},
|
|
||||||
{TypeWebDAV, []string{}, []string{"/", "/webdav", "/remote.php/dav/files/{user}", "/remote.php/webdav", "/dav/files/{user}", "/servlet/webdav.infostore/"}, "PROPFIND"},
|
|
||||||
{TypeWeb, []string{}, []string{}, "GET"},
|
|
||||||
}
|
|
||||||
|
|
||||||
func HttpOk(method, rawUrl string) bool {
|
|
||||||
req, err := http.NewRequest(method, rawUrl, nil)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if resp, err := client.Do(req); err != nil {
|
|
||||||
return false
|
|
||||||
} else if resp.StatusCode < 400 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h Heuristic) MatchDomain(match string) bool {
|
|
||||||
if len(h.Domains) == 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, m := range h.Domains {
|
|
||||||
if m == match {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h Heuristic) Discover(rawUrl, user string) *url.URL {
|
|
||||||
u, err := url.Parse(rawUrl)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if HttpOk(h.Method, u.String()) {
|
|
||||||
return u
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, p := range h.Paths {
|
|
||||||
strings.Replace(p, "{user}", user, -1)
|
|
||||||
u.Path = p
|
|
||||||
|
|
||||||
if HttpOk(h.Method, u.String()) {
|
|
||||||
return u
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func Discover(rawUrl, user, pass string) (result Account, err error) {
|
|
||||||
if rawUrl == "" {
|
|
||||||
return result, errors.New("service URL is empty")
|
|
||||||
}
|
|
||||||
|
|
||||||
u, err := url.Parse(rawUrl)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return result, err
|
|
||||||
}
|
|
||||||
|
|
||||||
u.Host = strings.ToLower(u.Host)
|
|
||||||
|
|
||||||
result.AccUser = u.User.Username()
|
|
||||||
result.AccPass, _ = u.User.Password()
|
|
||||||
|
|
||||||
// Extract user info
|
|
||||||
if user != "" {
|
|
||||||
result.AccUser = user
|
|
||||||
}
|
|
||||||
|
|
||||||
if pass != "" {
|
|
||||||
result.AccPass = pass
|
|
||||||
}
|
|
||||||
|
|
||||||
if user != "" || pass != "" {
|
|
||||||
u.User = url.UserPassword(result.AccUser, result.AccPass)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set default scheme
|
|
||||||
if u.Scheme == "" {
|
|
||||||
u.Scheme = "https"
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, h := range Heuristics {
|
|
||||||
if !h.MatchDomain(u.Host) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if serviceUrl := h.Discover(u.String(), result.AccUser); serviceUrl != nil {
|
|
||||||
serviceUrl.User = nil
|
|
||||||
|
|
||||||
if w := txt.Keywords(serviceUrl.Host); len(w) > 0 {
|
|
||||||
result.AccName = strings.Title(w[0])
|
|
||||||
} else {
|
|
||||||
result.AccName = serviceUrl.Host
|
|
||||||
}
|
|
||||||
|
|
||||||
result.AccType = h.ServiceType
|
|
||||||
result.AccURL = serviceUrl.String()
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, errors.New("could not connect")
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user