Log4j: Sanitize user input in logs like filenames and album titles #1814

This commit is contained in:
Michael Mayer
2021-12-14 17:07:38 +01:00
parent ccfa99543d
commit 9a8144c046
101 changed files with 449 additions and 361 deletions

View File

@@ -35,7 +35,7 @@ func SaveAlbumAsYaml(a entity.Album) {
if err := a.SaveAsYaml(fileName); err != nil {
log.Errorf("album: %s (update yaml)", err)
} else {
log.Debugf("album: updated yaml file %s", txt.Quote(filepath.Base(fileName)))
log.Debugf("album: updated yaml file %s", txt.LogParam(filepath.Base(fileName)))
}
}
@@ -85,10 +85,8 @@ func CreateAlbum(router *gin.RouterGroup) {
a := entity.NewAlbum(f.AlbumTitle, entity.AlbumDefault)
a.AlbumFavorite = f.AlbumFavorite
log.Debugf("album: creating %+v %+v", f, a)
if res := entity.Db().Create(a); res.Error != nil {
AbortAlreadyExists(c, txt.Quote(a.AlbumTitle))
AbortAlreadyExists(c, txt.LogParam(a.AlbumTitle))
return
}
@@ -198,7 +196,7 @@ func DeleteAlbum(router *gin.RouterGroup) {
SaveAlbumAsYaml(a)
event.SuccessMsg(i18n.MsgAlbumDeleted, txt.Quote(a.AlbumTitle))
event.SuccessMsg(i18n.MsgAlbumDeleted, txt.LogParam(a.AlbumTitle))
c.JSON(http.StatusOK, a)
})
@@ -327,7 +325,7 @@ func CloneAlbums(router *gin.RouterGroup) {
}
if len(added) > 0 {
event.SuccessMsg(i18n.MsgSelectionAddedTo, txt.Quote(a.Title()))
event.SuccessMsg(i18n.MsgSelectionAddedTo, txt.LogParam(a.Title()))
PublishAlbumEvent(EntityUpdated, a.AlbumUID, c)
@@ -377,9 +375,9 @@ func AddPhotosToAlbum(router *gin.RouterGroup) {
if len(added) > 0 {
if len(added) == 1 {
event.SuccessMsg(i18n.MsgEntryAddedTo, txt.Quote(a.Title()))
event.SuccessMsg(i18n.MsgEntryAddedTo, txt.LogParam(a.Title()))
} else {
event.SuccessMsg(i18n.MsgEntriesAddedTo, len(added), txt.Quote(a.Title()))
event.SuccessMsg(i18n.MsgEntriesAddedTo, len(added), txt.LogParam(a.Title()))
}
RemoveFromAlbumCoverCache(a.AlbumUID)
@@ -428,9 +426,9 @@ func RemovePhotosFromAlbum(router *gin.RouterGroup) {
if len(removed) > 0 {
if len(removed) == 1 {
event.SuccessMsg(i18n.MsgEntryRemovedFrom, txt.Quote(a.Title()))
event.SuccessMsg(i18n.MsgEntryRemovedFrom, txt.LogParam(a.Title()))
} else {
event.SuccessMsg(i18n.MsgEntriesRemovedFrom, len(removed), txt.Quote(txt.Quote(a.Title())))
event.SuccessMsg(i18n.MsgEntriesRemovedFrom, len(removed), txt.LogParam(txt.LogParam(a.Title())))
}
RemoveFromAlbumCoverCache(a.AlbumUID)
@@ -480,12 +478,12 @@ func DownloadAlbum(router *gin.RouterGroup) {
for _, file := range files {
if file.FileHash == "" {
log.Warnf("download: empty file hash, skipped %s", txt.Quote(file.FileName))
log.Warnf("download: empty file hash, skipped %s", txt.LogParam(file.FileName))
continue
}
if file.FileSidecar {
log.Debugf("download: skipped sidecar %s", txt.Quote(file.FileName))
log.Debugf("download: skipped sidecar %s", txt.LogParam(file.FileName))
continue
}
@@ -505,12 +503,12 @@ func DownloadAlbum(router *gin.RouterGroup) {
Abort(c, http.StatusInternalServerError, i18n.ErrZipFailed)
return
}
log.Infof("download: added %s as %s", txt.Quote(file.FileName), txt.Quote(alias))
log.Infof("download: added %s as %s", txt.LogParam(file.FileName), txt.LogParam(alias))
} else {
log.Errorf("download: failed finding %s", txt.Quote(file.FileName))
log.Errorf("download: failed finding %s", txt.LogParam(file.FileName))
}
}
log.Infof("download: created %s [%s]", txt.Quote(zipFileName), time.Since(start))
log.Infof("download: created %s [%s]", txt.LogParam(zipFileName), time.Since(start))
})
}

View File

@@ -74,7 +74,7 @@ func Error(c *gin.Context, code int, err error, id i18n.Message, params ...inter
if err != nil {
resp.Details = err.Error()
log.Errorf("api: error %s with code %d in %s (%s)", txt.Quote(err.Error()), code, c.FullPath(), resp.String())
log.Errorf("api: error %s with code %d in %s (%s)", txt.LogParam(err.Error()), code, c.FullPath(), resp.String())
}
c.AbortWithStatusJSON(code, resp)

View File

@@ -88,7 +88,7 @@ func AlbumCover(router *gin.RouterGroup) {
c.Data(http.StatusOK, "image/svg+xml", albumIconSvg)
// Set missing flag so that the file doesn't show up in search results anymore.
log.Warnf("%s: %s is missing", albumCover, txt.Quote(f.FileName))
log.Warnf("%s: %s is missing", albumCover, txt.LogParam(f.FileName))
logError(albumCover, f.Update("FileMissing", true))
return
}
@@ -196,7 +196,7 @@ func LabelCover(router *gin.RouterGroup) {
fileName := photoprism.FileName(f.FileRoot, f.FileName)
if !fs.FileExists(fileName) {
log.Errorf("%s: file %s is missing", labelCover, txt.Quote(f.FileName))
log.Errorf("%s: file %s is missing", labelCover, txt.LogParam(f.FileName))
c.Data(http.StatusOK, "image/svg+xml", labelIconSvg)
// Set missing flag so that the file doesn't show up in search results anymore.

View File

@@ -56,7 +56,7 @@ func GetDownload(router *gin.RouterGroup) {
fileName := photoprism.FileName(f.FileRoot, f.FileName)
if !fs.FileExists(fileName) {
log.Errorf("download: file %s is missing", txt.Quote(f.FileName))
log.Errorf("download: file %s is missing", txt.LogParam(f.FileName))
c.Data(404, "image/svg+xml", brokenIconSvg)
// Set missing flag so that the file doesn't show up in search results anymore.

View File

@@ -58,17 +58,17 @@ func DeleteFile(router *gin.RouterGroup) {
mediaFile, err := photoprism.NewMediaFile(fileName)
if err != nil {
log.Errorf("photo: %s (delete %s)", err, txt.Quote(baseName))
log.Errorf("photo: %s (delete %s)", err, txt.LogParam(baseName))
AbortEntityNotFound(c)
return
}
if err := mediaFile.Remove(); err != nil {
log.Errorf("photo: %s (delete %s from folder)", err, txt.Quote(baseName))
log.Errorf("photo: %s (delete %s from folder)", err, txt.LogParam(baseName))
}
if err := file.Delete(true); err != nil {
log.Errorf("photo: %s (delete %s from index)", err, txt.Quote(baseName))
log.Errorf("photo: %s (delete %s from index)", err, txt.LogParam(baseName))
AbortDeleteFailed(c)
return
}

View File

@@ -97,7 +97,7 @@ func FolderCover(router *gin.RouterGroup) {
c.Data(http.StatusOK, "image/svg+xml", folderIconSvg)
// Set missing flag so that the file doesn't show up in search results anymore.
log.Warnf("%s: %s is missing", folderCover, txt.Quote(f.FileName))
log.Warnf("%s: %s is missing", folderCover, txt.LogParam(f.FileName))
logError(folderCover, f.Update("FileMissing", true))
return
}

View File

@@ -69,10 +69,10 @@ func StartImport(router *gin.RouterGroup) {
var opt photoprism.ImportOptions
if f.Move {
event.InfoMsg(i18n.MsgMovingFilesFrom, txt.Quote(filepath.Base(path)))
event.InfoMsg(i18n.MsgMovingFilesFrom, txt.LogParam(filepath.Base(path)))
opt = photoprism.ImportOptionsMove(path)
} else {
event.InfoMsg(i18n.MsgCopyingFilesFrom, txt.Quote(filepath.Base(path)))
event.InfoMsg(i18n.MsgCopyingFilesFrom, txt.LogParam(filepath.Base(path)))
opt = photoprism.ImportOptionsCopy(path)
}
@@ -85,9 +85,9 @@ func StartImport(router *gin.RouterGroup) {
if subPath != "" && path != conf.ImportPath() && fs.IsEmpty(path) {
if err := os.Remove(path); err != nil {
log.Errorf("import: failed deleting empty folder %s: %s", txt.Quote(path), err)
log.Errorf("import: failed deleting empty folder %s: %s", txt.LogParam(path), err)
} else {
log.Infof("import: deleted empty folder %s", txt.Quote(path))
log.Infof("import: deleted empty folder %s", txt.LogParam(path))
}
}

View File

@@ -56,7 +56,7 @@ func StartIndexing(router *gin.RouterGroup) {
}
if len(indOpt.Path) > 1 {
event.InfoMsg(i18n.MsgIndexingFiles, txt.Quote(indOpt.Path))
event.InfoMsg(i18n.MsgIndexingFiles, txt.LogParam(indOpt.Path))
} else {
event.InfoMsg(i18n.MsgIndexingOriginals)
}

View File

@@ -32,7 +32,7 @@ func SavePhotoAsYaml(p entity.Photo) {
if err := p.SaveAsYaml(fileName); err != nil {
log.Errorf("photo: %s (update yaml)", err)
} else {
log.Debugf("photo: updated yaml file %s", txt.Quote(filepath.Base(fileName)))
log.Debugf("photo: updated yaml file %s", txt.LogParam(filepath.Base(fileName)))
}
}
@@ -145,7 +145,7 @@ func GetPhotoDownload(router *gin.RouterGroup) {
fileName := photoprism.FileName(f.FileRoot, f.FileName)
if !fs.FileExists(fileName) {
log.Errorf("photo: file %s is missing", txt.Quote(f.FileName))
log.Errorf("photo: file %s is missing", txt.LogParam(f.FileName))
c.Data(http.StatusNotFound, "image/svg+xml", photoIconSvg)
// Set missing flag so that the file doesn't show up in search results anymore.

View File

@@ -154,17 +154,17 @@ func GetThumb(router *gin.RouterGroup) {
fileName := photoprism.FileName(f.FileRoot, f.FileName)
if !fs.FileExists(fileName) {
log.Errorf("%s: file %s is missing", logPrefix, txt.Quote(f.FileName))
log.Errorf("%s: file %s is missing", logPrefix, txt.LogParam(f.FileName))
c.Data(http.StatusOK, "image/svg+xml", brokenIconSvg)
// Set missing flag so that the file doesn't show up in search results anymore.
logError(logPrefix, f.Update("FileMissing", true))
if f.AllFilesMissing() {
log.Infof("%s: deleting photo, all files missing for %s", logPrefix, txt.Quote(f.FileName))
log.Infof("%s: deleting photo, all files missing for %s", logPrefix, txt.LogParam(f.FileName))
if _, err := f.RelatedPhoto().Delete(false); err != nil {
log.Errorf("%s: %s while deleting %s", logPrefix, err, txt.Quote(f.FileName))
log.Errorf("%s: %s while deleting %s", logPrefix, err, txt.LogParam(f.FileName))
}
}

View File

@@ -60,7 +60,7 @@ func PhotoUnstack(router *gin.RouterGroup) {
unstackFile, err := photoprism.NewMediaFile(fileName)
if err != nil {
log.Errorf("photo: %s (unstack %s)", err, txt.Quote(baseName))
log.Errorf("photo: %s (unstack %s)", err, txt.LogParam(baseName))
AbortEntityNotFound(c)
return
}
@@ -69,7 +69,7 @@ func PhotoUnstack(router *gin.RouterGroup) {
stackPrimary, err := stackPhoto.PrimaryFile()
if err != nil {
log.Errorf("photo: can't find primary file for %s (unstack)", txt.Quote(baseName))
log.Errorf("photo: can't find primary file for %s (unstack)", txt.LogParam(baseName))
AbortUnexpected(c)
return
}
@@ -77,15 +77,15 @@ func PhotoUnstack(router *gin.RouterGroup) {
related, err := unstackFile.RelatedFiles(false)
if err != nil {
log.Errorf("photo: %s (unstack %s)", err, txt.Quote(baseName))
log.Errorf("photo: %s (unstack %s)", err, txt.LogParam(baseName))
AbortEntityNotFound(c)
return
} else if related.Len() == 0 {
log.Errorf("photo: found no files for %s (unstack)", txt.Quote(baseName))
log.Errorf("photo: found no files for %s (unstack)", txt.LogParam(baseName))
AbortEntityNotFound(c)
return
} else if related.Main == nil {
log.Errorf("photo: found no main file for %s (unstack)", txt.Quote(baseName))
log.Errorf("photo: found no main file for %s (unstack)", txt.LogParam(baseName))
AbortEntityNotFound(c)
return
}
@@ -95,7 +95,7 @@ func PhotoUnstack(router *gin.RouterGroup) {
if unstackFile.BasePrefix(false) == stackPhoto.PhotoName {
if conf.ReadOnly() {
log.Errorf("photo: can't rename files in read only mode (unstack %s)", txt.Quote(baseName))
log.Errorf("photo: can't rename files in read only mode (unstack %s)", txt.LogParam(baseName))
AbortFeatureDisabled(c)
return
}
@@ -103,7 +103,7 @@ func PhotoUnstack(router *gin.RouterGroup) {
destName := fmt.Sprintf("%s.%s%s", unstackFile.AbsPrefix(false), unstackFile.Checksum(), unstackFile.Extension())
if err := unstackFile.Move(destName); err != nil {
log.Errorf("photo: can't rename %s to %s (unstack)", txt.Quote(unstackFile.BaseName()), txt.Quote(filepath.Base(destName)))
log.Errorf("photo: can't rename %s to %s (unstack)", txt.LogParam(unstackFile.BaseName()), txt.LogParam(filepath.Base(destName)))
AbortUnexpected(c)
return
}
@@ -119,7 +119,7 @@ func PhotoUnstack(router *gin.RouterGroup) {
newPhoto.PhotoName = unstackFile.BasePrefix(false)
if err := newPhoto.Create(); err != nil {
log.Errorf("photo: %s (unstack %s)", err.Error(), txt.Quote(baseName))
log.Errorf("photo: %s (unstack %s)", err.Error(), txt.LogParam(baseName))
AbortSaveFailed(c)
return
}
@@ -139,17 +139,17 @@ func PhotoUnstack(router *gin.RouterGroup) {
newPhoto.ID, newPhoto.PhotoUID, r.RootRelName(),
relName, relRoot).Error; err != nil {
// Handle error...
log.Errorf("photo: %s (unstack %s)", err.Error(), txt.Quote(r.BaseName()))
log.Errorf("photo: %s (unstack %s)", err.Error(), txt.LogParam(r.BaseName()))
// Remove new photo from index.
if _, err := newPhoto.Delete(true); err != nil {
log.Errorf("photo: %s (unstack %s)", err.Error(), txt.Quote(r.BaseName()))
log.Errorf("photo: %s (unstack %s)", err.Error(), txt.LogParam(r.BaseName()))
}
// Revert file rename.
if unstackSingle {
if err := r.Move(photoprism.FileName(relRoot, relName)); err != nil {
log.Errorf("photo: %s (unstack %s)", err.Error(), txt.Quote(r.BaseName()))
log.Errorf("photo: %s (unstack %s)", err.Error(), txt.LogParam(r.BaseName()))
}
}
@@ -162,21 +162,21 @@ func PhotoUnstack(router *gin.RouterGroup) {
// Index unstacked files.
if res := ind.FileName(unstackFile.FileName(), photoprism.IndexOptionsSingle()); res.Failed() {
log.Errorf("photo: %s (unstack %s)", res.Err, txt.Quote(baseName))
log.Errorf("photo: %s (unstack %s)", res.Err, txt.LogParam(baseName))
AbortSaveFailed(c)
return
}
// Reset type for existing photo stack to image.
if err := stackPhoto.Update("PhotoType", entity.TypeImage); err != nil {
log.Errorf("photo: %s (unstack %s)", err, txt.Quote(baseName))
log.Errorf("photo: %s (unstack %s)", err, txt.LogParam(baseName))
AbortUnexpected(c)
return
}
// Re-index existing photo stack.
if res := ind.FileName(photoprism.FileName(stackPrimary.FileRoot, stackPrimary.FileName), photoprism.IndexOptionsSingle()); res.Failed() {
log.Errorf("photo: %s (unstack %s)", res.Err, txt.Quote(baseName))
log.Errorf("photo: %s (unstack %s)", res.Err, txt.LogParam(baseName))
AbortSaveFailed(c)
return
}

View File

@@ -95,7 +95,7 @@ func SharePreview(router *gin.RouterGroup) {
fileName := photoprism.FileName(f.FileRoot, f.FileName)
if !fs.FileExists(fileName) {
log.Errorf("share: file %s is missing (preview)", txt.Quote(f.FileName))
log.Errorf("share: file %s is missing (preview)", txt.LogParam(f.FileName))
c.Redirect(http.StatusTemporaryRedirect, conf.SitePreview())
return
}
@@ -125,7 +125,7 @@ func SharePreview(router *gin.RouterGroup) {
fileName := photoprism.FileName(f.FileRoot, f.FileName)
if !fs.FileExists(fileName) {
log.Errorf("share: file %s is missing (preview)", txt.Quote(f.FileName))
log.Errorf("share: file %s is missing (preview)", txt.LogParam(f.FileName))
c.Redirect(http.StatusTemporaryRedirect, conf.SitePreview())
return
}

View File

@@ -52,7 +52,7 @@ func Upload(router *gin.RouterGroup) {
p := path.Join(conf.ImportPath(), "upload", subPath)
if err := os.MkdirAll(p, os.ModePerm); err != nil {
log.Errorf("upload: failed creating folder %s", txt.Quote(subPath))
log.Errorf("upload: failed creating folder %s", txt.LogParam(subPath))
AbortBadRequest(c)
return
}
@@ -60,7 +60,7 @@ func Upload(router *gin.RouterGroup) {
for _, file := range files {
filename := path.Join(p, filepath.Base(file.Filename))
log.Debugf("upload: saving file %s", txt.Quote(file.Filename))
log.Debugf("upload: saving file %s", txt.LogParam(file.Filename))
if err := c.SaveUploadedFile(file, filename); err != nil {
log.Errorf("upload: failed saving file %s", filepath.Base(file.Filename))
@@ -88,7 +88,7 @@ func Upload(router *gin.RouterGroup) {
continue
}
log.Infof("nsfw: %s might be offensive", txt.Quote(filename))
log.Infof("nsfw: %s might be offensive", txt.LogParam(filename))
containsNSFW = true
}
@@ -96,7 +96,7 @@ func Upload(router *gin.RouterGroup) {
if containsNSFW {
for _, filename := range uploads {
if err := os.Remove(filename); err != nil {
log.Errorf("nsfw: could not delete %s", txt.Quote(filename))
log.Errorf("nsfw: could not delete %s", txt.LogParam(filename))
}
}

View File

@@ -30,7 +30,7 @@ func GetVideo(router *gin.RouterGroup) {
videoType, ok := video.Types[typeName]
if !ok {
log.Errorf("video: invalid type %s", txt.Quote(typeName))
log.Errorf("video: invalid type %s", txt.LogParam(typeName))
c.Data(http.StatusOK, "image/svg+xml", videoIconSvg)
return
}
@@ -62,7 +62,7 @@ func GetVideo(router *gin.RouterGroup) {
fileName := photoprism.FileName(f.FileRoot, f.FileName)
if mf, err := photoprism.NewMediaFile(fileName); err != nil {
log.Errorf("video: file %s is missing", txt.Quote(f.FileName))
log.Errorf("video: file %s is missing", txt.LogParam(f.FileName))
c.Data(http.StatusOK, "image/svg+xml", videoIconSvg)
// Set missing flag so that the file doesn't show up in search results anymore.
@@ -73,7 +73,7 @@ func GetVideo(router *gin.RouterGroup) {
conv := service.Convert()
if avcFile, err := conv.ToAvc(mf, service.Config().FFmpegEncoder()); err != nil {
log.Errorf("video: transcoding %s failed", txt.Quote(f.FileName))
log.Errorf("video: transcoding %s failed", txt.LogParam(f.FileName))
c.Data(http.StatusOK, "image/svg+xml", videoIconSvg)
return
} else {

View File

@@ -93,12 +93,12 @@ func CreateZip(router *gin.RouterGroup) {
for _, file := range files {
if file.FileHash == "" {
log.Warnf("download: empty file hash, skipped %s", txt.Quote(file.FileName))
log.Warnf("download: empty file hash, skipped %s", txt.LogParam(file.FileName))
continue
}
if file.FileSidecar {
log.Debugf("download: skipped sidecar %s", txt.Quote(file.FileName))
log.Debugf("download: skipped sidecar %s", txt.LogParam(file.FileName))
continue
}
@@ -117,16 +117,16 @@ func CreateZip(router *gin.RouterGroup) {
Error(c, http.StatusInternalServerError, err, i18n.ErrZipFailed)
return
}
log.Infof("download: added %s as %s", txt.Quote(file.FileName), txt.Quote(alias))
log.Infof("download: added %s as %s", txt.LogParam(file.FileName), txt.LogParam(alias))
} else {
log.Warnf("download: file %s is missing", txt.Quote(file.FileName))
log.Warnf("download: file %s is missing", txt.LogParam(file.FileName))
logError("download", file.Update("FileMissing", true))
}
}
elapsed := int(time.Since(start).Seconds())
log.Infof("download: created %s [%s]", txt.Quote(zipBaseName), time.Since(start))
log.Infof("download: created %s [%s]", txt.LogParam(zipBaseName), time.Since(start))
c.JSON(http.StatusOK, gin.H{"code": http.StatusOK, "message": i18n.Msg(i18n.MsgZipCreatedIn, elapsed), "filename": zipBaseName})
})
@@ -154,7 +154,7 @@ func DownloadZip(router *gin.RouterGroup) {
c.FileAttachment(zipFileName, zipBaseName)
if err := os.Remove(zipFileName); err != nil {
log.Errorf("download: failed removing %s (%s)", txt.Quote(zipFileName), err.Error())
log.Errorf("download: failed removing %s (%s)", txt.LogParam(zipFileName), err.Error())
}
})
}

View File

@@ -66,7 +66,7 @@ func Import() error {
api.RemoveFromFolderCache(entity.RootImport)
event.InfoMsg(i18n.MsgCopyingFilesFrom, txt.Quote(filepath.Base(path)))
event.InfoMsg(i18n.MsgCopyingFilesFrom, txt.LogParam(filepath.Base(path)))
var opt photoprism.ImportOptions

View File

@@ -34,7 +34,7 @@ func main() {
fileName := "rules.yml"
if !fs.FileExists(fileName) {
log.Panicf("classify: found no label rules in %s", txt.Quote(filepath.Base(fileName)))
log.Panicf("classify: found no label rules in %s", txt.LogParam(filepath.Base(fileName)))
}
yamlConfig, err := os.ReadFile(fileName)

View File

@@ -148,7 +148,7 @@ func (t *TensorFlow) loadModel() error {
modelPath := path.Join(t.modelsPath, t.modelName)
log.Infof("classify: loading %s", txt.Quote(filepath.Base(modelPath)))
log.Infof("classify: loading %s", txt.LogParam(filepath.Base(modelPath)))
// Load model
model, err := tf.LoadSavedModel(modelPath, t.modelTags, nil)

View File

@@ -113,7 +113,7 @@ func backupAction(ctx *cli.Context) error {
}
}
log.Infof("backing up database to %s", txt.Quote(indexFileName))
log.Infof("backing up database to %s", txt.LogParam(indexFileName))
}
var cmd *exec.Cmd
@@ -175,7 +175,7 @@ func backupAction(ctx *cli.Context) error {
albumsPath = conf.AlbumsPath()
}
log.Infof("backing up albums to %s", txt.Quote(albumsPath))
log.Infof("backing up albums to %s", txt.LogParam(albumsPath))
if count, err := photoprism.BackupAlbums(albumsPath, true); err != nil {
return err

View File

@@ -48,7 +48,7 @@ func convertAction(ctx *cli.Context) error {
convertPath = filepath.Join(convertPath, subPath)
}
log.Infof("converting originals in %s", txt.Quote(convertPath))
log.Infof("converting originals in %s", txt.LogParam(convertPath))
w := service.Convert()

View File

@@ -239,9 +239,9 @@ func facesIndexAction(ctx *cli.Context) error {
subPath := strings.TrimSpace(ctx.Args().First())
if subPath == "" {
log.Infof("finding faces in %s", txt.Quote(conf.OriginalsPath()))
log.Infof("finding faces in %s", txt.LogParam(conf.OriginalsPath()))
} else {
log.Infof("finding faces in %s", txt.Quote(filepath.Join(conf.OriginalsPath(), subPath)))
log.Infof("finding faces in %s", txt.LogParam(filepath.Join(conf.OriginalsPath(), subPath)))
}
if conf.ReadOnly() {

View File

@@ -57,9 +57,9 @@ func indexAction(ctx *cli.Context) error {
subPath := strings.TrimSpace(ctx.Args().First())
if subPath == "" {
log.Infof("indexing originals in %s", txt.Quote(conf.OriginalsPath()))
log.Infof("indexing originals in %s", txt.LogParam(conf.OriginalsPath()))
} else {
log.Infof("indexing originals in %s", txt.Quote(filepath.Join(conf.OriginalsPath(), subPath)))
log.Infof("indexing originals in %s", txt.LogParam(filepath.Join(conf.OriginalsPath(), subPath)))
}
if conf.ReadOnly() {

View File

@@ -39,7 +39,7 @@ func passwdAction(ctx *cli.Context) error {
user := entity.Admin
log.Infof("please enter a new password for %s (at least 6 characters)\n", txt.Quote(user.Username()))
log.Infof("please enter a new password for %s (at least 6 characters)\n", txt.LogParam(user.Username()))
newPassword := getPassword("New Password: ")
@@ -57,7 +57,7 @@ func passwdAction(ctx *cli.Context) error {
return err
}
log.Infof("changed password for %s\n", txt.Quote(user.Username()))
log.Infof("changed password for %s\n", txt.LogParam(user.Username()))
conf.Shutdown()

View File

@@ -56,9 +56,9 @@ func purgeAction(ctx *cli.Context) error {
subPath := strings.TrimSpace(ctx.Args().First())
if subPath == "" {
log.Infof("purge: removing missing files in %s", txt.Quote(filepath.Base(conf.OriginalsPath())))
log.Infof("purge: removing missing files in %s", txt.LogParam(filepath.Base(conf.OriginalsPath())))
} else {
log.Infof("purge: removing missing files in %s", txt.Quote(fs.RelName(filepath.Join(conf.OriginalsPath(), subPath), filepath.Dir(conf.OriginalsPath()))))
log.Infof("purge: removing missing files in %s", txt.LogParam(fs.RelName(filepath.Join(conf.OriginalsPath(), subPath), filepath.Dir(conf.OriginalsPath()))))
}
if conf.ReadOnly() {

View File

@@ -123,7 +123,7 @@ func restoreAction(ctx *cli.Context) error {
log.Warnf("replacing existing index with %d photos", counts.Photos)
}
log.Infof("restoring index from %s", txt.Quote(indexFileName))
log.Infof("restoring index from %s", txt.LogParam(indexFileName))
sqlBackup, err := os.ReadFile(indexFileName)
@@ -199,9 +199,9 @@ func restoreAction(ctx *cli.Context) error {
}
if !fs.PathExists(albumsPath) {
log.Warnf("albums backup path %s not found", txt.Quote(albumsPath))
log.Warnf("albums backup path %s not found", txt.LogParam(albumsPath))
} else {
log.Infof("restoring albums from %s", txt.Quote(albumsPath))
log.Infof("restoring albums from %s", txt.LogParam(albumsPath))
if count, err := photoprism.RestoreAlbums(albumsPath, true); err != nil {
return err

View File

@@ -95,7 +95,7 @@ func startAction(ctx *cli.Context) error {
if child != nil {
if !fs.Overwrite(conf.PIDFilename(), []byte(strconv.Itoa(child.Pid))) {
log.Fatalf("failed writing process id to %s", txt.Quote(conf.PIDFilename()))
log.Fatalf("failed writing process id to %s", txt.LogParam(conf.PIDFilename()))
}
log.Infof("daemon started with process id %v\n", child.Pid)

View File

@@ -22,7 +22,7 @@ var StopCommand = cli.Command{
func stopAction(ctx *cli.Context) error {
conf := config.NewConfig(ctx)
log.Infof("looking for pid in %s", txt.Quote(conf.PIDFilename()))
log.Infof("looking for pid in %s", txt.LogParam(conf.PIDFilename()))
dcxt := new(daemon.Context)
dcxt.PidFileName = conf.PIDFilename()

View File

@@ -34,7 +34,7 @@ func thumbsAction(ctx *cli.Context) error {
return err
}
log.Infof("creating thumbnails in %s", txt.Quote(conf.ThumbPath()))
log.Infof("creating thumbnails in %s", txt.LogParam(conf.ThumbPath()))
rs := service.Resample()

View File

@@ -183,7 +183,7 @@ func usersDeleteAction(ctx *cli.Context) error {
}
actionPrompt := promptui.Prompt{
Label: fmt.Sprintf("Delete %s?", txt.Quote(userName)),
Label: fmt.Sprintf("Delete %s?", txt.LogParam(userName)),
IsConfirm: true,
}
@@ -193,7 +193,7 @@ func usersDeleteAction(ctx *cli.Context) error {
} else if err := m.Delete(); err != nil {
return err
} else {
log.Infof("%s deleted", txt.Quote(userName))
log.Infof("%s deleted", txt.LogParam(userName))
}
} else {
log.Infof("keeping user")
@@ -242,7 +242,7 @@ func usersUpdateAction(ctx *cli.Context) error {
if err != nil {
return err
}
fmt.Printf("password successfully changed: %v\n", u.Username())
fmt.Printf("password successfully changed: %s\n", txt.LogParam(u.Username()))
}
if ctx.IsSet("fullname") {
@@ -261,7 +261,7 @@ func usersUpdateAction(ctx *cli.Context) error {
return err
}
fmt.Printf("user successfully updated: %v\n", u.Username())
fmt.Printf("user successfully updated: %s\n", txt.LogParam(u.Username()))
return nil
})

View File

@@ -124,7 +124,7 @@ func NewConfig(ctx *cli.Context) *Config {
if err := c.options.Load(configFile); err != nil {
log.Warnf("config: %s", err)
} else {
log.Debugf("config: options loaded from %s", txt.Quote(configFile))
log.Debugf("config: options loaded from %s", txt.LogParam(configFile))
}
}
@@ -192,7 +192,7 @@ func (c *Config) Init() error {
}
if cpuName := cpuid.CPU.BrandName; cpuName != "" {
log.Debugf("config: running on %s, %s memory detected", txt.Quote(cpuid.CPU.BrandName), humanize.Bytes(TotalMem))
log.Debugf("config: running on %s, %s memory detected", txt.LogParam(cpuid.CPU.BrandName), humanize.Bytes(TotalMem))
}
// Check memory requirements.

View File

@@ -33,9 +33,9 @@ func findExecutable(configBin, defaultBin string) (result string) {
func (c *Config) CreateDirectories() error {
createError := func(path string, err error) (result error) {
if fs.FileExists(path) {
result = fmt.Errorf("%s is a file, not a folder: please check your configuration", txt.Quote(path))
result = fmt.Errorf("%s is a file, not a folder: please check your configuration", txt.LogParam(path))
} else {
result = fmt.Errorf("can't create %s: please check configuration and permissions", txt.Quote(path))
result = fmt.Errorf("can't create %s: please check configuration and permissions", txt.LogParam(path))
}
log.Debug(err)

View File

@@ -181,7 +181,7 @@ func (s Settings) StackMeta() bool {
// Load user settings from file.
func (s *Settings) Load(fileName string) error {
if !fs.FileExists(fileName) {
return fmt.Errorf("settings file not found: %s", txt.Quote(fileName))
return fmt.Errorf("settings file not found: %s", txt.LogParam(fileName))
}
yamlConfig, err := os.ReadFile(fileName)

View File

@@ -28,7 +28,7 @@ func FromCache(hash, area string, size Size, thumbPath string) (fileName string,
// FileName returns the crop file name based on cache path, size, and area.
func FileName(hash, area string, width, height int, thumbPath string) (fileName string, err error) {
if len(hash) < 4 {
return "", fmt.Errorf("crop: invalid file hash %s", txt.Quote(hash))
return "", fmt.Errorf("crop: invalid file hash %s", txt.LogParam(hash))
}
if len(thumbPath) < 1 {

View File

@@ -92,7 +92,7 @@ func ImageFromThumb(thumbName string, area Area, size Size, cache bool) (img ima
// ThumbFileName returns the ideal thumb file name.
func ThumbFileName(hash string, area Area, size Size, thumbPath string) (string, error) {
if len(hash) < 4 {
return "", fmt.Errorf("invalid file hash %s", txt.Quote(hash))
return "", fmt.Errorf("invalid file hash %s", txt.LogParam(hash))
}
if len(thumbPath) < 1 {

View File

@@ -3,6 +3,8 @@ package entity
import (
"fmt"
"time"
"github.com/photoprism/photoprism/pkg/txt"
)
type Addresses []Address
@@ -62,7 +64,7 @@ func FirstOrCreateAddress(m *Address) *Address {
// String returns an identifier that can be used in logs.
func (m *Address) String() string {
return fmt.Sprintf("%s, %s %s, %s", m.AddressLine1, m.AddressZip, m.AddressCity, m.AddressCountry)
return txt.LogParam(fmt.Sprintf("%s, %s %s, %s", m.AddressLine1, m.AddressZip, m.AddressCity, m.AddressCountry))
}
// Unknown returns true if the address is unknown.

View File

@@ -38,7 +38,7 @@ func TestAddress_String(t *testing.T) {
t.Run("success", func(t *testing.T) {
address := Address{ID: 1234567, AddressLine1: "Line 1", AddressLine2: "Line 2", AddressCity: "Berlin", AddressCountry: "DE"}
addressString := address.String()
assert.Equal(t, "Line 1, Berlin, DE", addressString)
assert.Equal(t, "'Line 1, Berlin, DE'", addressString)
})
}

View File

@@ -336,15 +336,15 @@ func (m *Album) BeforeCreate(scope *gorm.Scope) error {
// String returns the id or name as string.
func (m *Album) String() string {
if m.AlbumSlug != "" {
return m.AlbumSlug
return txt.LogParam(m.AlbumSlug)
}
if m.AlbumTitle != "" {
return txt.Quote(m.AlbumTitle)
return txt.LogParam(m.AlbumTitle)
}
if m.AlbumUID != "" {
return m.AlbumUID
return txt.LogParam(m.AlbumUID)
}
return "[unknown album]"

View File

@@ -123,7 +123,7 @@ func FirstOrCreateCamera(m *Camera) *Camera {
cameraCache.SetDefault(m.CameraSlug, &result)
return &result
} else {
log.Errorf("camera: %s (create %s)", err.Error(), txt.Quote(m.String()))
log.Errorf("camera: %s (create %s)", err.Error(), txt.LogParam(m.String()))
}
return &UnknownCamera
@@ -131,7 +131,7 @@ func FirstOrCreateCamera(m *Camera) *Camera {
// String returns an identifier that can be used in logs.
func (m *Camera) String() string {
return m.CameraName
return txt.LogParam(m.CameraName)
}
// Unknown returns true if the camera is not a known make or model.

View File

@@ -119,7 +119,7 @@ func TestCamera_String(t *testing.T) {
t.Run("model XXX make Nikon", func(t *testing.T) {
camera := NewCamera("XXX", "Nikon")
cameraString := camera.String()
assert.Equal(t, "Nikon XXX", cameraString)
assert.Equal(t, "'Nikon XXX'", cameraString)
})
t.Run("model XXX make Unknown", func(t *testing.T) {
camera := NewCamera("XXX", "")

View File

@@ -56,10 +56,10 @@ func (list Tables) WaitForMigration(db *gorm.DB) {
for i := 0; i <= attempts; i++ {
count := RowCount{}
if err := db.Raw(fmt.Sprintf("SELECT COUNT(*) AS count FROM %s", name)).Scan(&count).Error; err == nil {
log.Tracef("entity: %s migrated", txt.Quote(name))
log.Tracef("entity: %s migrated", txt.LogParam(name))
break
} else {
log.Debugf("entity: waiting for %s migration (%s)", txt.Quote(name), err.Error())
log.Debugf("entity: waiting for %s migration (%s)", txt.LogParam(name), err.Error())
}
if i == attempts {
@@ -78,7 +78,7 @@ func (list Tables) Truncate(db *gorm.DB) {
// log.Debugf("entity: removed all data from %s", name)
break
} else if err.Error() != "record not found" {
log.Debugf("entity: %s in %s", err, txt.Quote(name))
log.Debugf("entity: %s in %s", err, txt.LogParam(name))
}
}
}
@@ -92,7 +92,7 @@ func (list Tables) Migrate(db *gorm.DB, runFailed bool) {
time.Sleep(time.Second)
if err := db.AutoMigrate(entity).Error; err != nil {
log.Errorf("entity: failed migrating %s", txt.Quote(name))
log.Errorf("entity: failed migrating %s", txt.LogParam(name))
panic(err)
}
}

View File

@@ -138,8 +138,8 @@ func TestNewDetails(t *testing.T) {
t.Fatal(err)
}
t.Logf("PHOTO: %#v", p)
t.Logf("DETAILS: %#v", d)
// t.Logf("PHOTO: %#v", p)
// t.Logf("DETAILS: %#v", d)
})
}

View File

@@ -56,7 +56,7 @@ func PurgeDuplicate(fileName, fileRoot string) error {
}
if err := UnscopedDb().Delete(Duplicate{}, "file_name = ? AND file_root = ?", fileName, fileRoot).Error; err != nil {
log.Errorf("duplicate: %s in %s (purge)", err, txt.Quote(fileName))
log.Errorf("duplicate: %s in %s (purge)", err, txt.LogParam(fileName))
return err
}
@@ -101,7 +101,7 @@ func (m *Duplicate) Save() error {
}
if err := UnscopedDb().Save(m).Error; err != nil {
log.Errorf("duplicate: %s in %s (save)", err, txt.Quote(m.FileName))
log.Errorf("duplicate: %s in %s (save)", err, txt.LogParam(m.FileName))
return err
}

View File

@@ -206,23 +206,23 @@ func (m File) Missing() bool {
// DeletePermanently permanently removes a file from the index.
func (m *File) DeletePermanently() error {
if m.ID < 1 || m.FileUID == "" {
return fmt.Errorf("invalid file id %d / uid %s", m.ID, txt.Quote(m.FileUID))
return fmt.Errorf("invalid file id %d / uid %s", m.ID, txt.LogParam(m.FileUID))
}
if err := UnscopedDb().Delete(Marker{}, "file_uid = ?", m.FileUID).Error; err != nil {
log.Errorf("file %s: %s while removing markers", txt.Quote(m.FileUID), err)
log.Errorf("file %s: %s while removing markers", txt.LogParam(m.FileUID), err)
}
if err := UnscopedDb().Delete(FileShare{}, "file_id = ?", m.ID).Error; err != nil {
log.Errorf("file %s: %s while removing share info", txt.Quote(m.FileUID), err)
log.Errorf("file %s: %s while removing share info", txt.LogParam(m.FileUID), err)
}
if err := UnscopedDb().Delete(FileSync{}, "file_id = ?", m.ID).Error; err != nil {
log.Errorf("file %s: %s while removing remote sync info", txt.Quote(m.FileUID), err)
log.Errorf("file %s: %s while removing remote sync info", txt.LogParam(m.FileUID), err)
}
if err := m.ReplaceHash(""); err != nil {
log.Errorf("file %s: %s while removing covers", txt.Quote(m.FileUID), err)
log.Errorf("file %s: %s while removing covers", txt.LogParam(m.FileUID), err)
}
return UnscopedDb().Delete(m).Error
@@ -237,9 +237,9 @@ func (m *File) ReplaceHash(newHash string) error {
// Log values.
if m.FileHash != "" && newHash == "" {
log.Tracef("file %s: removing hash %s", txt.Quote(m.FileUID), txt.Quote(m.FileHash))
log.Tracef("file %s: removing hash %s", txt.LogParam(m.FileUID), txt.LogParam(m.FileHash))
} else if m.FileHash != "" && newHash != "" {
log.Tracef("file %s: hash %s changed to %s", txt.Quote(m.FileUID), txt.Quote(m.FileHash), txt.Quote(newHash))
log.Tracef("file %s: hash %s changed to %s", txt.LogParam(m.FileUID), txt.LogParam(m.FileHash), txt.LogParam(newHash))
// Reset error when hash changes.
m.FileError = ""
}
@@ -275,7 +275,7 @@ func (m *File) ReplaceHash(newHash string) error {
// Delete deletes the entity from the database.
func (m *File) Delete(permanently bool) error {
if m.ID < 1 || m.FileUID == "" {
return fmt.Errorf("invalid file id %d / uid %s", m.ID, txt.Quote(m.FileUID))
return fmt.Errorf("invalid file id %d / uid %s", m.ID, txt.LogParam(m.FileUID))
}
if permanently {
@@ -326,7 +326,7 @@ func (m *File) Create() error {
}
if _, err := m.SaveMarkers(); err != nil {
log.Errorf("file %s: %s while saving markers", txt.Quote(m.FileUID), err)
log.Errorf("file %s: %s while saving markers", txt.LogParam(m.FileUID), err)
return err
}
@@ -349,12 +349,12 @@ func (m *File) Save() error {
}
if err := UnscopedDb().Save(m).Error; err != nil {
log.Errorf("file %s: %s while saving", txt.Quote(m.FileUID), err)
log.Errorf("file %s: %s while saving", txt.LogParam(m.FileUID), err)
return err
}
if _, err := m.SaveMarkers(); err != nil {
log.Errorf("file %s: %s while saving markers", txt.Quote(m.FileUID), err)
log.Errorf("file %s: %s while saving markers", txt.LogParam(m.FileUID), err)
return err
}
@@ -384,7 +384,7 @@ func (m *File) Updates(values interface{}) error {
// Rename updates the name and path of this file.
func (m *File) Rename(fileName, rootName, filePath, fileBase string) error {
log.Debugf("file %s: renaming %s to %s", txt.Quote(m.FileUID), txt.Quote(m.FileName), txt.Quote(fileName))
log.Debugf("file %s: renaming %s to %s", txt.LogParam(m.FileUID), txt.LogParam(m.FileName), txt.LogParam(fileName))
// Update database row.
if err := m.Updates(map[string]interface{}{
@@ -428,7 +428,7 @@ func (m *File) Undelete() error {
return err
}
log.Debugf("file %s: removed missing flag from %s", txt.Quote(m.FileUID), txt.Quote(m.FileName))
log.Debugf("file %s: removed missing flag from %s", txt.LogParam(m.FileUID), txt.LogParam(m.FileName))
m.FileMissing = false
m.DeletedAt = nil
@@ -562,7 +562,7 @@ func (m *File) Markers() *Markers {
} else if m.FileUID == "" {
m.markers = &Markers{}
} else if res, err := FindMarkers(m.FileUID); err != nil {
log.Warnf("file %s: %s while loading markers", txt.Quote(m.FileUID), err)
log.Warnf("file %s: %s while loading markers", txt.LogParam(m.FileUID), err)
m.markers = &Markers{}
} else {
m.markers = &res

View File

@@ -179,7 +179,7 @@ func (m *Folder) Create() error {
if err := a.Create(); err != nil {
log.Errorf("folder: %s (add album)", err)
} else {
log.Infof("folder: added album %s (%s)", txt.Quote(a.AlbumTitle), a.AlbumFilter)
log.Infof("folder: added album %s (%s)", txt.LogParam(a.AlbumTitle), a.AlbumFilter)
}
}

View File

@@ -124,7 +124,7 @@ func FirstOrCreateLens(m *Lens) *Lens {
lensCache.SetDefault(m.LensSlug, &result)
return &result
} else {
log.Errorf("lens: %s (create %s)", err.Error(), txt.Quote(m.String()))
log.Errorf("lens: %s (create %s)", err.Error(), txt.LogParam(m.String()))
}
return &UnknownLens
@@ -132,7 +132,7 @@ func FirstOrCreateLens(m *Lens) *Lens {
// String returns an identifier that can be used in logs.
func (m *Lens) String() string {
return m.LensName
return txt.LogParam(m.LensName)
}
// Unknown returns true if the lens is not a known make or model.

View File

@@ -33,7 +33,7 @@ func TestLens_TableName(t *testing.T) {
func TestLens_String(t *testing.T) {
lens := NewLens("F500-99", "samsung")
assert.Equal(t, "Samsung F500-99", lens.String())
assert.Equal(t, "'Samsung F500-99'", lens.String())
}
func TestFirstOrCreateLens(t *testing.T) {

View File

@@ -192,5 +192,5 @@ func FindValidLinks(token, share string) (result Links) {
// String returns an human readable identifier for logging.
func (m *Link) String() string {
return m.LinkUID
return txt.LogParam(m.LinkUID)
}

View File

@@ -232,7 +232,7 @@ func (m *Marker) SetFace(f *Face, dist float64) (updated bool, err error) {
} else if reported, err := f.ResolveCollision(m.Embeddings()); err != nil {
return false, err
} else if reported {
log.Warnf("marker %s: face %s has ambiguous subjects %s <> %s, subject source %s", txt.Quote(m.MarkerUID), txt.Quote(f.ID), txt.Quote(m.SubjUID), txt.Quote(f.SubjUID), SrcString(m.SubjSrc))
log.Warnf("marker %s: face %s has ambiguous subjects %s <> %s, subject source %s", txt.LogParam(m.MarkerUID), txt.LogParam(f.ID), txt.LogParam(m.SubjUID), txt.LogParam(f.SubjUID), SrcString(m.SubjSrc))
return false, nil
} else {
return false, nil
@@ -428,10 +428,10 @@ func (m *Marker) Subject() (subj *Subject) {
// Create subject?
if m.SubjSrc != SrcAuto && m.MarkerName != "" && m.SubjUID == "" {
if subj = NewSubject(m.MarkerName, SubjPerson, m.SubjSrc); subj == nil {
log.Errorf("marker %s: invalid subject %s", txt.Quote(m.MarkerUID), txt.Quote(m.MarkerName))
log.Errorf("marker %s: invalid subject %s", txt.LogParam(m.MarkerUID), txt.LogParam(m.MarkerName))
return nil
} else if subj = FirstOrCreateSubject(subj); subj == nil {
log.Debugf("marker %s: invalid subject %s", txt.Quote(m.MarkerUID), txt.Quote(m.MarkerName))
log.Debugf("marker %s: invalid subject %s", txt.LogParam(m.MarkerUID), txt.LogParam(m.MarkerName))
return nil
} else {
m.subject = subj
@@ -457,9 +457,9 @@ func (m *Marker) ClearSubject(src string) error {
// Find and (soft) delete unused subjects.
start := time.Now()
if count, err := DeleteOrphanPeople(); err != nil {
log.Errorf("marker %s: %s while removing unused subjects [%s]", txt.Quote(m.MarkerUID), err, time.Since(start))
log.Errorf("marker %s: %s while removing unused subjects [%s]", txt.LogParam(m.MarkerUID), err, time.Since(start))
} else if count > 0 {
log.Debugf("marker %s: removed %s [%s]", txt.Quote(m.MarkerUID), english.Plural(count, "person", "people"), time.Since(start))
log.Debugf("marker %s: removed %s [%s]", txt.LogParam(m.MarkerUID), english.Plural(count, "person", "people"), time.Since(start))
}
}()
@@ -472,7 +472,7 @@ func (m *Marker) ClearSubject(src string) error {
} else if resolved, err := m.face.ResolveCollision(m.Embeddings()); err != nil {
return err
} else if resolved {
log.Debugf("marker %s: resolved ambiguous subjects for face %s", txt.Quote(m.MarkerUID), txt.Quote(m.face.ID))
log.Debugf("marker %s: resolved ambiguous subjects for face %s", txt.LogParam(m.MarkerUID), txt.LogParam(m.face.ID))
}
// Clear references.
@@ -498,21 +498,21 @@ func (m *Marker) Face() (f *Face) {
// Add face if size
if m.SubjSrc != SrcAuto && m.FaceID == "" {
if m.Size < face.ClusterSizeThreshold || m.Score < face.ClusterScoreThreshold {
log.Debugf("marker %s: skipped adding face due to low-quality (size %d, score %d)", txt.Quote(m.MarkerUID), m.Size, m.Score)
log.Debugf("marker %s: skipped adding face due to low-quality (size %d, score %d)", txt.LogParam(m.MarkerUID), m.Size, m.Score)
return nil
} else if emb := m.Embeddings(); emb.Empty() {
log.Warnf("marker %s: found no face embeddings", txt.Quote(m.MarkerUID))
log.Warnf("marker %s: found no face embeddings", txt.LogParam(m.MarkerUID))
return nil
} else if f = NewFace(m.SubjUID, m.SubjSrc, emb); f == nil {
log.Warnf("marker %s: failed assigning face", txt.Quote(m.MarkerUID))
log.Warnf("marker %s: failed assigning face", txt.LogParam(m.MarkerUID))
return nil
} else if f.Unsuitable() {
log.Infof("marker %s: face %s is unsuitable for clustering and matching", txt.Quote(m.MarkerUID), f.ID)
log.Infof("marker %s: face %s is unsuitable for clustering and matching", txt.LogParam(m.MarkerUID), f.ID)
} else if f = FirstOrCreateFace(f); f == nil {
log.Warnf("marker %s: failed assigning face", txt.Quote(m.MarkerUID))
log.Warnf("marker %s: failed assigning face", txt.LogParam(m.MarkerUID))
return nil
} else if err := f.MatchMarkers(Faceless); err != nil {
log.Errorf("marker %s: %s while matching with faces", txt.Quote(m.MarkerUID), err)
log.Errorf("marker %s: %s while matching with faces", txt.LogParam(m.MarkerUID), err)
}
m.face = f
@@ -695,7 +695,7 @@ func FindFaceMarker(faceId string) *Marker {
if err := Db().Where("face_id = ?", faceId).
Where("thumb <> '' AND marker_invalid = 0").
Order("face_dist ASC, q DESC").First(&result).Error; err != nil {
log.Warnf("markers: found no marker for face %s", txt.Quote(faceId))
log.Warnf("markers: found no marker for face %s", txt.LogParam(faceId))
return nil
}
@@ -714,7 +714,7 @@ func CreateMarkerIfNotExists(m *Marker) (*Marker, error) {
} else if err := m.Create(); err != nil {
return m, err
} else {
log.Debugf("markers: added %s marker %s for %s", TypeString(m.MarkerType), txt.Quote(m.MarkerUID), txt.Quote(m.FileUID))
log.Debugf("markers: added %s marker %s for %s", TypeString(m.MarkerType), txt.LogParam(m.MarkerUID), txt.LogParam(m.FileUID))
}
return m, nil

View File

@@ -210,15 +210,15 @@ func SavePhotoForm(model Photo, form form.Photo) error {
func (m *Photo) String() string {
if m.PhotoUID == "" {
if m.PhotoName != "" {
return txt.Quote(m.PhotoName)
return txt.LogParam(m.PhotoName)
} else if m.OriginalName != "" {
return txt.Quote(m.OriginalName)
return txt.LogParam(m.OriginalName)
}
return "(unknown)"
}
return "uid " + txt.Quote(m.PhotoUID)
return "uid " + txt.LogParam(m.PhotoUID)
}
// FirstOrCreate fetches an existing row from the database or inserts a new one.
@@ -561,12 +561,12 @@ func (m *Photo) AddLabels(labels classify.Labels) {
labelEntity := FirstOrCreateLabel(NewLabel(classifyLabel.Title(), classifyLabel.Priority))
if labelEntity == nil {
log.Errorf("index: label %s should not be nil - bug? (%s)", txt.Quote(classifyLabel.Title()), m)
log.Errorf("index: label %s should not be nil - bug? (%s)", txt.LogParam(classifyLabel.Title()), m)
continue
}
if labelEntity.Deleted() {
log.Debugf("index: skipping deleted label %s (%s)", txt.Quote(classifyLabel.Title()), m)
log.Debugf("index: skipping deleted label %s (%s)", txt.LogParam(classifyLabel.Title()), m)
continue
}
@@ -721,7 +721,7 @@ func (m *Photo) Restore() error {
// Delete deletes the photo from the index.
func (m *Photo) Delete(permanently bool) (files Files, err error) {
if m.ID < 1 || m.PhotoUID == "" {
return files, fmt.Errorf("invalid photo id %d / uid %s", m.ID, txt.Quote(m.PhotoUID))
return files, fmt.Errorf("invalid photo id %d / uid %s", m.ID, txt.LogParam(m.PhotoUID))
}
if permanently {
@@ -742,7 +742,7 @@ func (m *Photo) Delete(permanently bool) (files Files, err error) {
// DeletePermanently permanently removes a photo from the index.
func (m *Photo) DeletePermanently() (files Files, err error) {
if m.ID < 1 || m.PhotoUID == "" {
return files, fmt.Errorf("invalid photo id %d / uid %s", m.ID, txt.Quote(m.PhotoUID))
return files, fmt.Errorf("invalid photo id %d / uid %s", m.ID, txt.LogParam(m.PhotoUID))
}
files = m.AllFiles()

View File

@@ -52,7 +52,7 @@ func (m *Photo) EstimateCountry() {
m.PhotoCountry = countryCode
m.PlaceSrc = SrcEstimate
m.EstimatedAt = TimePointer()
log.Debugf("photo: estimated country for %s is %s", m, txt.Quote(m.CountryName()))
log.Debugf("photo: estimated country for %s is %s", m, txt.LogParam(m.CountryName()))
}
}
@@ -109,7 +109,7 @@ func (m *Photo) EstimateLocation(force bool) {
Order(gorm.Expr("ABS(JulianDay(taken_at) - JulianDay(?))", m.TakenAt)).Limit(2).
Preload("Place").Find(&mostRecent).Error
default:
log.Warnf("photo: unsupported sql dialect %s", txt.Quote(DbDialect()))
log.Warnf("photo: unsupported sql dialect %s", txt.LogParam(DbDialect()))
return
}
@@ -146,7 +146,7 @@ func (m *Photo) EstimateLocation(force bool) {
}
}
} else if recentPhoto.HasCountry() {
log.Debugf("photo: estimated country for %s is %s", m, txt.Quote(m.CountryName()))
log.Debugf("photo: estimated country for %s is %s", m, txt.LogParam(m.CountryName()))
m.RemoveLocation(SrcEstimate, false)
m.RemoveLocationLabels()
m.PhotoCountry = recentPhoto.PhotoCountry

View File

@@ -77,7 +77,7 @@ func (m *Photo) SetPosition(pos geo.Position, source string, force bool) {
if m.Place == nil {
log.Warnf("photo: failed updating position of %s", m)
} else {
log.Debugf("photo: approximate place of %s is %s (id %s)", m, txt.Quote(m.Place.Label()), m.PlaceID)
log.Debugf("photo: approximate place of %s is %s (id %s)", m, txt.LogParam(m.Place.Label()), m.PlaceID)
}
}
}
@@ -106,7 +106,7 @@ func (m *Photo) AdoptPlace(other Photo, source string, force bool) {
m.UpdateTimeZone(other.TimeZone)
log.Debugf("photo: %s now located at %s (id %s)", m.String(), txt.Quote(m.Place.Label()), m.PlaceID)
log.Debugf("photo: %s now located at %s (id %s)", m.String(), txt.LogParam(m.Place.Label()), m.PlaceID)
}
// RemoveLocation removes the current location.

View File

@@ -66,7 +66,7 @@ func (m *Photo) UpdateTitle(labels classify.Labels) error {
// TODO: User defined title format
if names != "" {
log.Debugf("photo: %s title based on %s (%s)", m.String(), english.Plural(len(people), "person", "people"), txt.Quote(names))
log.Debugf("photo: %s title based on %s (%s)", m.String(), english.Plural(len(people), "person", "people"), txt.LogParam(names))
if l := len([]rune(names)); l > 35 {
m.SetTitle(names, SrcAuto)
@@ -80,7 +80,7 @@ func (m *Photo) UpdateTitle(labels classify.Labels) error {
m.SetTitle(fmt.Sprintf("%s / %s / %s", names, loc.City(), m.TakenAt.Format("2006")), SrcAuto)
}
} else if title := labels.Title(loc.Name()); title != "" {
log.Debugf("photo: %s title based on label %s", m.String(), txt.Quote(title))
log.Debugf("photo: %s title based on label %s", m.String(), txt.LogParam(title))
if loc.NoCity() || loc.LongCity() || loc.CityContains(title) {
m.SetTitle(fmt.Sprintf("%s / %s / %s", txt.Title(title), loc.CountryName(), m.TakenAt.Format("2006")), SrcAuto)
} else {
@@ -105,7 +105,7 @@ func (m *Photo) UpdateTitle(labels classify.Labels) error {
knownLocation = true
if names != "" {
log.Debugf("photo: %s title based on %s (%s)", m.String(), english.Plural(len(people), "person", "people"), txt.Quote(names))
log.Debugf("photo: %s title based on %s (%s)", m.String(), english.Plural(len(people), "person", "people"), txt.LogParam(names))
if l := len([]rune(names)); l > 35 {
m.SetTitle(names, SrcAuto)
@@ -119,7 +119,7 @@ func (m *Photo) UpdateTitle(labels classify.Labels) error {
m.SetTitle(fmt.Sprintf("%s / %s / %s", names, m.Place.City(), m.TakenAt.Format("2006")), SrcAuto)
}
} else if title := labels.Title(fileTitle); title != "" {
log.Debugf("photo: %s title based on label %s", m.String(), txt.Quote(title))
log.Debugf("photo: %s title based on label %s", m.String(), txt.LogParam(title))
if m.Place.NoCity() || m.Place.LongCity() || m.Place.CityContains(title) {
m.SetTitle(fmt.Sprintf("%s / %s / %s", txt.Title(title), m.Place.CountryName(), m.TakenAt.Format("2006")), SrcAuto)
} else {
@@ -161,7 +161,7 @@ func (m *Photo) UpdateTitle(labels classify.Labels) error {
}
if m.PhotoTitle != oldTitle {
log.Debugf("photo: %s has new title %s [%s]", m.String(), txt.Quote(m.PhotoTitle), time.Since(start))
log.Debugf("photo: %s has new title %s [%s]", m.String(), txt.LogParam(m.PhotoTitle), time.Since(start))
}
return nil

View File

@@ -54,7 +54,7 @@ func FindPlace(id string) *Place {
place := Place{}
if err := Db().Where("id = ?", id).First(&place).Error; err != nil {
log.Debugf("place: %s no found", txt.Quote(id))
log.Debugf("place: %s no found", txt.LogParam(id))
return nil
} else {
return &place

View File

@@ -104,7 +104,7 @@ func (m *Subject) Delete() error {
subjectMutex.Lock()
defer subjectMutex.Unlock()
log.Infof("subject: deleting %s %s", TypeString(m.SubjType), txt.Quote(m.SubjName))
log.Infof("subject: deleting %s %s", TypeString(m.SubjType), txt.LogParam(m.SubjName))
event.EntitiesDeleted("subjects", []string{m.SubjUID})
@@ -141,7 +141,7 @@ func (m *Subject) Restore() error {
if m.Deleted() {
m.DeletedAt = nil
log.Infof("subject: restoring %s %s", TypeString(m.SubjType), txt.Quote(m.SubjName))
log.Infof("subject: restoring %s %s", TypeString(m.SubjType), txt.LogParam(m.SubjName))
event.EntitiesCreated("subjects", []*Subject{m})
@@ -179,7 +179,7 @@ func FirstOrCreateSubject(m *Subject) *Subject {
if found := FindSubjectByName(m.SubjName); found != nil {
return found
} else if createErr := m.Create(); createErr == nil {
log.Infof("subject: added %s %s", TypeString(m.SubjType), txt.Quote(m.SubjName))
log.Infof("subject: added %s %s", TypeString(m.SubjType), txt.LogParam(m.SubjName))
event.EntitiesCreated("subjects", []*Subject{m})
@@ -194,7 +194,7 @@ func FirstOrCreateSubject(m *Subject) *Subject {
} else if found = FindSubjectByName(m.SubjName); found != nil {
return found
} else {
log.Errorf("subject: %s while creating %s", createErr, txt.Quote(m.SubjName))
log.Errorf("subject: %s while creating %s", createErr, txt.LogParam(m.SubjName))
}
return nil
@@ -327,8 +327,6 @@ func (m *Subject) SaveForm(f form.Subject) (changed bool, err error) {
}
if err := m.Updates(values); err == nil {
log.Debugf("subject: updated values %v", values)
event.EntitiesUpdated("subjects", []*Subject{m})
if m.IsPerson() {
@@ -349,7 +347,7 @@ func (m *Subject) UpdateName(name string) (*Subject, error) {
if err := m.SetName(name); err != nil {
return m, err
} else if err := m.Updates(Values{"SubjName": m.SubjName, "SubjSlug": m.SubjSlug}); err == nil {
log.Infof("subject: renamed %s %s", TypeString(m.SubjType), txt.Quote(m.SubjName))
log.Infof("subject: renamed %s %s", TypeString(m.SubjType), txt.LogParam(m.SubjName))
event.EntitiesUpdated("subjects", []*Subject{m})

View File

@@ -176,7 +176,7 @@ func FindUserByName(userName string) *User {
if err := Db().Preload("Address").Where("user_name = ?", userName).First(&result).Error; err == nil {
return &result
} else {
log.Debugf("user %s not found", txt.Quote(userName))
log.Debugf("user %s not found", txt.LogParam(userName))
return nil
}
}
@@ -192,7 +192,7 @@ func FindUserByUID(uid string) *User {
if err := Db().Preload("Address").Where("user_uid = ?", uid).First(&result).Error; err == nil {
return &result
} else {
log.Debugf("user %s not found", txt.Quote(uid))
log.Debugf("user %s not found", txt.LogParam(uid))
return nil
}
}
@@ -214,14 +214,14 @@ func (m *User) Deleted() bool {
// String returns an identifier that can be used in logs.
func (m *User) String() string {
if n := m.Username(); n != "" {
return n
return txt.LogParam(n)
}
if m.FullName != "" {
return m.FullName
return txt.LogParam(m.FullName)
}
return m.UserUID
return txt.LogParam(m.UserUID)
}
// Username returns the normalized username.
@@ -256,7 +256,7 @@ func (m *User) SetPassword(password string) error {
}
if len(password) < 4 {
return fmt.Errorf("new password for %s must be at least 4 characters", txt.Quote(m.Username()))
return fmt.Errorf("new password for %s must be at least 4 characters", txt.LogParam(m.Username()))
}
pw := NewPassword(m.UserUID, password)
@@ -398,7 +398,7 @@ func CreateWithPassword(uc form.UserCreate) error {
RoleAdmin: true,
}
if len(uc.Password) < 4 {
return fmt.Errorf("new password for %s must be at least 4 characters", txt.Quote(u.Username()))
return fmt.Errorf("new password for %s must be at least 4 characters", txt.LogParam(u.Username()))
}
err := u.Validate()
if err != nil {
@@ -412,7 +412,7 @@ func CreateWithPassword(uc form.UserCreate) error {
if err := tx.Create(&pw).Error; err != nil {
return err
}
log.Infof("created user %v with uid %v", txt.Quote(u.Username()), txt.Quote(u.UserUID))
log.Infof("created user %s with uid %s", txt.LogParam(u.Username()), txt.LogParam(u.UserUID))
return nil
})
}

View File

@@ -22,7 +22,7 @@ func TestPublishSubscribe(t *testing.T) {
msg := <-s.Receiver
t.Logf("receive msg with topic %s: %v\n", msg.Name, msg.Fields)
// t.Logf("receive msg with topic %s: %v\n", msg.Name, msg.Fields)
assert.Equal(t, "foo.bar", msg.Name)
assert.Equal(t, Data{"id": 13}, msg.Fields)

View File

@@ -92,13 +92,13 @@ func Detect(fileName string, findLandmarks bool, minSize int) (faces Faces, err
}
if !fs.FileExists(fileName) {
return faces, fmt.Errorf("faces: file '%s' not found", txt.Quote(filepath.Base(fileName)))
return faces, fmt.Errorf("faces: file '%s' not found", txt.LogParam(filepath.Base(fileName)))
}
det, params, err := d.Detect(fileName)
if err != nil {
return faces, fmt.Errorf("faces: %v (detect faces)", err)
return faces, fmt.Errorf("faces: %s (detect faces)", err)
}
if det == nil {

View File

@@ -57,7 +57,7 @@ func (t *Net) Detect(fileName string, minSize int, cacheCrop bool, expected int)
}
if img, err := crop.ImageFromThumb(fileName, f.CropArea(), CropSize, cacheCrop); err != nil {
log.Errorf("faces: failed to decode image: %v", err)
log.Errorf("faces: failed to decode image: %s", err)
} else if embeddings := t.getEmbeddings(img); !embeddings.Empty() {
faces[i].Embeddings = embeddings
}
@@ -82,7 +82,7 @@ func (t *Net) loadModel() error {
modelPath := path.Join(t.modelPath)
log.Infof("faces: loading %s", txt.Quote(filepath.Base(modelPath)))
log.Infof("faces: loading %s", txt.LogParam(filepath.Base(modelPath)))
// Load model
model, err := tf.LoadSavedModel(modelPath, t.modelTags, nil)
@@ -101,7 +101,7 @@ func (t *Net) getEmbeddings(img image.Image) Embeddings {
tensor, err := imageToTensor(img, CropSize.Width, CropSize.Height)
if err != nil {
log.Errorf("faces: failed to convert image to tensor: %v", err)
log.Errorf("faces: failed to convert image to tensor: %s", err)
}
// TODO: pre-whiten image as in facenet

View File

@@ -182,7 +182,7 @@ func (c *Config) Refresh() (err error) {
// Load backend api credentials from a YAML file.
func (c *Config) Load() error {
if !fs.FileExists(c.FileName) {
return fmt.Errorf("settings file not found: %s", txt.Quote(c.FileName))
return fmt.Errorf("settings file not found: %s", txt.LogParam(c.FileName))
}
mutex.Lock()

View File

@@ -46,7 +46,7 @@ func FindLocation(id string) (result Location, err error) {
if len(id) == 0 {
return result, fmt.Errorf("empty cell id")
} else if n := len(id); n < 4 || n > 16 {
return result, fmt.Errorf("invalid cell id %s", txt.Quote(id))
return result, fmt.Errorf("invalid cell id %s", txt.LogParam(id))
}
// Remember start time.
@@ -133,7 +133,7 @@ func FindLocation(id string) (result Location, err error) {
}
cache.SetDefault(id, result)
log.Tracef("places: cached cell %s [%s]", txt.Quote(id), time.Since(start))
log.Tracef("places: cached cell %s [%s]", txt.LogParam(id), time.Since(start))
result.Cached = false

View File

@@ -51,7 +51,7 @@ func (data *Data) Exif(fileName string, fileType fs.FileFormat) (err error) {
defer func() {
if e := recover(); e != nil {
err = fmt.Errorf("metadata: %s in %s (exif panic)\nstack: %s", e, txt.Quote(filepath.Base(fileName)), debug.Stack())
err = fmt.Errorf("metadata: %s in %s (exif panic)\nstack: %s", e, txt.LogParam(filepath.Base(fileName)), debug.Stack())
}
}()
@@ -62,7 +62,7 @@ func (data *Data) Exif(fileName string, fileType fs.FileFormat) (err error) {
return err
}
logName := txt.Quote(filepath.Base(fileName))
logName := txt.LogParam(filepath.Base(fileName))
if data.All == nil {
data.All = make(map[string]string)

View File

@@ -18,14 +18,14 @@ import (
func RawExif(fileName string, fileType fs.FileFormat) (rawExif []byte, err error) {
defer func() {
if e := recover(); e != nil {
err = fmt.Errorf("metadata: %s in %s (raw exif panic)\nstack: %s", e, txt.Quote(filepath.Base(fileName)), debug.Stack())
err = fmt.Errorf("metadata: %s in %s (raw exif panic)\nstack: %s", e, txt.LogParam(filepath.Base(fileName)), debug.Stack())
}
}()
// Extract raw EXIF block.
var parsed bool
logName := txt.Quote(filepath.Base(fileName))
logName := txt.LogParam(filepath.Base(fileName))
if fileType == fs.FormatJpeg {
jpegMp := jpegstructure.NewJpegMediaParser()

View File

@@ -23,7 +23,7 @@ func JSON(jsonName, originalName string) (data Data, err error) {
func (data *Data) JSON(jsonName, originalName string) (err error) {
defer func() {
if e := recover(); e != nil {
err = fmt.Errorf("metadata: %s in %s (json panic)\nstack: %s", e, txt.Quote(filepath.Base(jsonName)), debug.Stack())
err = fmt.Errorf("metadata: %s in %s (json panic)\nstack: %s", e, txt.LogParam(filepath.Base(jsonName)), debug.Stack())
}
}()
@@ -31,7 +31,7 @@ func (data *Data) JSON(jsonName, originalName string) (err error) {
data.All = make(map[string]string)
}
quotedName := txt.Quote(filepath.Base(jsonName))
quotedName := txt.LogParam(filepath.Base(jsonName))
if !fs.FileExists(jsonName) {
return fmt.Errorf("metadata: %s not found", quotedName)

View File

@@ -29,7 +29,7 @@ func (data *Data) Exiftool(jsonData []byte, originalName string) (err error) {
j := gjson.GetBytes(jsonData, "@flatten|@join")
if !j.IsObject() {
return fmt.Errorf("metadata: data is not an object in %s (exiftool)", txt.Quote(filepath.Base(originalName)))
return fmt.Errorf("metadata: data is not an object in %s (exiftool)", txt.LogParam(filepath.Base(originalName)))
}
jsonStrings := make(map[string]string)
@@ -40,7 +40,7 @@ func (data *Data) Exiftool(jsonData []byte, originalName string) (err error) {
}
if fileName, ok := jsonStrings["FileName"]; ok && fileName != "" && originalName != "" && fileName != originalName {
return fmt.Errorf("metadata: original name %s does not match %s (exiftool)", txt.Quote(originalName), txt.Quote(fileName))
return fmt.Errorf("metadata: original name %s does not match %s (exiftool)", txt.LogParam(originalName), txt.LogParam(fileName))
}
v := reflect.ValueOf(data).Elem()

View File

@@ -19,14 +19,14 @@ func XMP(fileName string) (data Data, err error) {
func (data *Data) XMP(fileName string) (err error) {
defer func() {
if e := recover(); e != nil {
err = fmt.Errorf("metadata: %s in %s (xmp panic)\nstack: %s", e, txt.Quote(filepath.Base(fileName)), debug.Stack())
err = fmt.Errorf("metadata: %s in %s (xmp panic)\nstack: %s", e, txt.LogParam(filepath.Base(fileName)), debug.Stack())
}
}()
doc := XmpDocument{}
if err := doc.Load(fileName); err != nil {
return fmt.Errorf("metadata: can't read %s (xmp)", txt.Quote(filepath.Base(fileName)))
return fmt.Errorf("metadata: can't read %s (xmp)", txt.LogParam(filepath.Base(fileName)))
}
if doc.Title() != "" {

View File

@@ -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 fs.MimeType(filename) != "image/jpeg" {
return result, fmt.Errorf("nsfw: %s is not a jpeg file", txt.Quote(filepath.Base(filename)))
return result, fmt.Errorf("nsfw: %s is not a jpeg file", txt.LogParam(filepath.Base(filename)))
}
imageBuffer, err := os.ReadFile(filename)
@@ -76,7 +76,7 @@ func (t *Detector) Labels(img []byte) (result Labels, err error) {
// Return best labels
result = t.getLabels(output[0].Value().([][]float32)[0])
log.Debugf("nsfw: image classified as %+v", result)
log.Tracef("nsfw: image classified as %+v", result)
return result, nil
}
@@ -118,7 +118,7 @@ func (t *Detector) loadModel() error {
return nil
}
log.Infof("nsfw: loading %s", txt.Quote(filepath.Base(t.modelPath)))
log.Infof("nsfw: loading %s", txt.LogParam(filepath.Base(t.modelPath)))
// Load model
model, err := tf.LoadSavedModel(t.modelPath, t.modelTags, nil)

View File

@@ -36,7 +36,7 @@ func BackupAlbums(backupPath string, force bool) (count int, result error) {
log.Errorf("album: %s (update yaml)", err)
result = err
} else {
log.Tracef("backup: saved album yaml file %s", txt.Quote(filepath.Base(fileName)))
log.Tracef("backup: saved album yaml file %s", txt.LogParam(filepath.Base(fileName)))
count++
}
}
@@ -87,14 +87,14 @@ func RestoreAlbums(backupPath string, force bool) (count int, result error) {
a := entity.Album{}
if err := a.LoadFromYaml(fileName); err != nil {
log.Errorf("restore: %s in %s", err, txt.Quote(filepath.Base(fileName)))
log.Errorf("restore: %s in %s", err, txt.LogParam(filepath.Base(fileName)))
result = err
} else if a.AlbumType == "" || len(a.Photos) == 0 && a.AlbumFilter == "" {
log.Debugf("restore: skipping %s", txt.Quote(filepath.Base(fileName)))
log.Debugf("restore: skipping %s", txt.LogParam(filepath.Base(fileName)))
} else if err := a.Find(); err == nil {
log.Infof("%s: %s already exists", a.AlbumType, txt.Quote(a.AlbumTitle))
log.Infof("%s: %s already exists", a.AlbumType, txt.LogParam(a.AlbumTitle))
} else if err := a.Create(); err != nil {
log.Errorf("%s: %s in %s", a.AlbumType, err, txt.Quote(filepath.Base(fileName)))
log.Errorf("%s: %s in %s", a.AlbumType, err, txt.LogParam(filepath.Base(fileName)))
} else {
count++
}

View File

@@ -82,7 +82,7 @@ func (w *CleanUp) Start(opt CleanUpOptions) (thumbs int, orphans int, err error)
}
hash := base[:i]
logName := txt.Quote(fs.RelName(fileName, thumbPath))
logName := txt.LogParam(fs.RelName(fileName, thumbPath))
if ok := fileHashes[hash]; ok {
// Do nothing.
@@ -119,7 +119,7 @@ func (w *CleanUp) Start(opt CleanUpOptions) (thumbs int, orphans int, err error)
if opt.Dry {
orphans++
log.Infof("cleanup: orphan photo %s would be removed", txt.Quote(p.PhotoUID))
log.Infof("cleanup: orphan photo %s would be removed", txt.LogParam(p.PhotoUID))
continue
}

View File

@@ -15,13 +15,13 @@ import (
// Colors returns the ColorPerception of an image (only JPEG supported).
func (m *MediaFile) Colors(thumbPath string) (perception colors.ColorPerception, err error) {
if !m.IsJpeg() {
return perception, fmt.Errorf("%s is not a jpeg", txt.Quote(m.BaseName()))
return perception, fmt.Errorf("%s is not a jpeg", txt.LogParam(m.BaseName()))
}
img, err := m.Resample(thumbPath, thumb.Colors)
if err != nil {
log.Debugf("colors: %s in %s (resample)", err, txt.Quote(m.BaseName()))
log.Debugf("colors: %s in %s (resample)", err, txt.LogParam(m.BaseName()))
return perception, err
}

View File

@@ -82,7 +82,7 @@ func (c *Convert) Start(path string) (err error) {
}
ignore.Log = func(fileName string) {
log.Infof("convert: ignoring %s", txt.Quote(filepath.Base(fileName)))
log.Infof("convert: ignoring %s", txt.LogParam(filepath.Base(fileName)))
}
err = godirwalk.Walk(path, &godirwalk.Options{
@@ -403,7 +403,7 @@ func (c *Convert) AvcConvertCommand(f *MediaFile, avcName, codecName string) (re
)
}
} else {
return nil, useMutex, fmt.Errorf("convert: file type %s not supported in %s", f.FileType(), txt.Quote(f.BaseName()))
return nil, useMutex, fmt.Errorf("convert: file type %s not supported in %s", f.FileType(), txt.LogParam(f.BaseName()))
}
return result, useMutex, nil

View File

@@ -14,7 +14,7 @@ type ConvertJob struct {
func ConvertWorker(jobs <-chan ConvertJob) {
logError := func(err error, job ConvertJob) {
fileName := job.file.RelName(job.convert.conf.OriginalsPath())
log.Errorf("convert: %s for %s", strings.TrimSpace(err.Error()), txt.Quote(fileName))
log.Errorf("convert: %s for %s", strings.TrimSpace(err.Error()), txt.LogParam(fileName))
}
for job := range jobs {

View File

@@ -24,16 +24,16 @@ func Delete(p entity.Photo) error {
for _, file := range files {
fileName := FileName(file.FileRoot, file.FileName)
log.Debugf("delete: removing file %s", txt.Quote(file.FileName))
log.Debugf("delete: removing file %s", txt.LogParam(file.FileName))
if f, err := NewMediaFile(fileName); err == nil {
if sidecarJson := f.SidecarJsonName(); fs.FileExists(sidecarJson) {
log.Debugf("delete: removing json sidecar %s", txt.Quote(filepath.Base(sidecarJson)))
log.Debugf("delete: removing json sidecar %s", txt.LogParam(filepath.Base(sidecarJson)))
logWarn("delete", os.Remove(sidecarJson))
}
if exifJson, err := f.ExifToolJsonName(); err == nil && fs.FileExists(exifJson) {
log.Debugf("delete: removing exiftool sidecar %s", txt.Quote(filepath.Base(exifJson)))
log.Debugf("delete: removing exiftool sidecar %s", txt.LogParam(filepath.Base(exifJson)))
logWarn("delete", os.Remove(exifJson))
}
@@ -47,7 +47,7 @@ func Delete(p entity.Photo) error {
// Remove sidecar backup.
if fs.FileExists(yamlFileName) {
log.Debugf("delete: removing yaml sidecar %s", txt.Quote(filepath.Base(yamlFileName)))
log.Debugf("delete: removing yaml sidecar %s", txt.LogParam(filepath.Base(yamlFileName)))
logWarn("delete", os.Remove(yamlFileName))
}

View File

@@ -78,13 +78,13 @@ func (w *Faces) Audit(fix bool) (err error) {
log.Infof("face %s: ambiguous subject at dist %f, Ø %f from %d samples, collision Ø %f", f1.ID, dist, r, f1.Samples, f1.CollisionRadius)
if f1.SubjUID != "" {
log.Infof("face %s: subject %s (%s %s)", f1.ID, txt.Quote(subj[f1.SubjUID].SubjName), f1.SubjUID, entity.SrcString(f1.FaceSrc))
log.Infof("face %s: subject %s (%s %s)", f1.ID, txt.LogParam(subj[f1.SubjUID].SubjName), f1.SubjUID, entity.SrcString(f1.FaceSrc))
} else {
log.Infof("face %s: has no subject (%s)", f1.ID, entity.SrcString(f1.FaceSrc))
}
if f2.SubjUID != "" {
log.Infof("face %s: subject %s (%s %s)", f2.ID, txt.Quote(subj[f2.SubjUID].SubjName), f2.SubjUID, entity.SrcString(f2.FaceSrc))
log.Infof("face %s: subject %s (%s %s)", f2.ID, txt.LogParam(subj[f2.SubjUID].SubjName), f2.SubjUID, entity.SrcString(f2.FaceSrc))
} else {
log.Infof("face %s: has no subject (%s)", f2.ID, entity.SrcString(f2.FaceSrc))
}
@@ -115,7 +115,7 @@ func (w *Faces) Audit(fix bool) (err error) {
log.Error(err)
} else {
for _, m := range markers {
log.Infof("marker %s: %s subject %s conflicts with face %s subject %s", m.MarkerUID, entity.SrcString(m.SubjSrc), txt.Quote(subj[m.SubjUID].SubjName), m.FaceID, txt.Quote(subj[faceMap[m.FaceID].SubjUID].SubjName))
log.Infof("marker %s: %s subject %s conflicts with face %s subject %s", m.MarkerUID, entity.SrcString(m.SubjSrc), txt.LogParam(subj[m.SubjUID].SubjName), m.FaceID, txt.LogParam(subj[faceMap[m.FaceID].SubjUID].SubjName))
}
}

View File

@@ -165,7 +165,7 @@ func (imp *Import) Start(opt ImportOptions) fs.Done {
}
if mf.FileSize() == 0 {
log.Infof("import: skipped empty file %s", txt.Quote(mf.BaseName()))
log.Infof("import: skipped empty file %s", txt.LogParam(mf.BaseName()))
return nil
}
@@ -219,9 +219,9 @@ func (imp *Import) Start(opt ImportOptions) fs.Done {
for _, directory := range directories {
if fs.IsEmpty(directory) {
if err := os.Remove(directory); err != nil {
log.Errorf("import: failed deleting empty folder %s (%s)", txt.Quote(fs.RelName(directory, importPath)), err)
log.Errorf("import: failed deleting empty folder %s (%s)", txt.LogParam(fs.RelName(directory, importPath)), err)
} else {
log.Infof("import: deleted empty folder %s", txt.Quote(fs.RelName(directory, importPath)))
log.Infof("import: deleted empty folder %s", txt.LogParam(fs.RelName(directory, importPath)))
}
}
}
@@ -235,7 +235,7 @@ func (imp *Import) Start(opt ImportOptions) fs.Done {
}
if err := os.Remove(file); err != nil {
log.Errorf("import: failed removing %s (%s)", txt.Quote(fs.RelName(file, importPath)), err.Error())
log.Errorf("import: failed removing %s (%s)", txt.LogParam(fs.RelName(file, importPath)), err.Error())
}
}
}
@@ -278,7 +278,7 @@ func (imp *Import) DestinationFilename(mainFile *MediaFile, mediaFile *MediaFile
if f, err := entity.FirstFileByHash(mediaFile.Hash()); err == nil {
existingFilename := FileName(f.FileRoot, f.FileName)
if fs.FileExists(existingFilename) {
return existingFilename, fmt.Errorf("%s is identical to %s (sha1 %s)", txt.Quote(filepath.Base(mediaFile.FileName())), txt.Quote(f.FileName), mediaFile.Hash())
return existingFilename, fmt.Errorf("%s is identical to %s (sha1 %s)", txt.LogParam(filepath.Base(mediaFile.FileName())), txt.LogParam(f.FileName), mediaFile.Hash())
} else {
return existingFilename, nil
}
@@ -294,7 +294,7 @@ func (imp *Import) DestinationFilename(mainFile *MediaFile, mediaFile *MediaFile
for fs.FileExists(result) {
if mediaFile.Hash() == fs.Hash(result) {
return result, fmt.Errorf("%s already exists", txt.Quote(fs.RelName(result, imp.originalsPath())))
return result, fmt.Errorf("%s already exists", txt.LogParam(fs.RelName(result, imp.originalsPath())))
}
iteration++

View File

@@ -30,15 +30,15 @@ func ImportWorker(jobs <-chan ImportJob) {
importPath := job.ImportOpt.Path
if related.Main == nil {
log.Warnf("import: %s belongs to no supported media file", txt.Quote(fs.RelName(job.FileName, importPath)))
log.Warnf("import: %s belongs to no supported media file", txt.LogParam(fs.RelName(job.FileName, importPath)))
continue
}
if related.Main.NeedsExifToolJson() {
if jsonName, err := imp.convert.ToJson(related.Main); err != nil {
log.Debugf("import: %s in %s (extract metadata)", txt.Quote(err.Error()), txt.Quote(related.Main.BaseName()))
log.Debugf("import: %s in %s (extract metadata)", txt.LogParam(err.Error()), txt.LogParam(related.Main.BaseName()))
} else if err := related.Main.ReadExifToolJson(); err != nil {
log.Errorf("import: %s in %s (read metadata)", txt.Quote(err.Error()), txt.Quote(related.Main.BaseName()))
log.Errorf("import: %s in %s (read metadata)", txt.LogParam(err.Error()), txt.LogParam(related.Main.BaseName()))
} else {
log.Debugf("import: created %s", filepath.Base(jsonName))
}
@@ -60,7 +60,7 @@ func ImportWorker(jobs <-chan ImportJob) {
if fs.PathExists(destDir) {
// Do nothing.
} else if err := os.MkdirAll(destDir, os.ModePerm); err != nil {
log.Errorf("import: failed creating folder for %s (%s)", txt.Quote(f.BaseName()), err.Error())
log.Errorf("import: failed creating folder for %s (%s)", txt.LogParam(f.BaseName()), err.Error())
} else {
destDirRel := fs.RelName(destDir, imp.originalsPath())
@@ -73,20 +73,20 @@ func ImportWorker(jobs <-chan ImportJob) {
if related.Main.HasSameName(f) {
destMainFileName = destFileName
log.Infof("import: moving main %s file %s to %s", f.FileType(), txt.Quote(relFileName), txt.Quote(fs.RelName(destFileName, imp.originalsPath())))
log.Infof("import: moving main %s file %s to %s", f.FileType(), txt.LogParam(relFileName), txt.LogParam(fs.RelName(destFileName, imp.originalsPath())))
} else {
log.Infof("import: moving related %s file %s to %s", f.FileType(), txt.Quote(relFileName), txt.Quote(fs.RelName(destFileName, imp.originalsPath())))
log.Infof("import: moving related %s file %s to %s", f.FileType(), txt.LogParam(relFileName), txt.LogParam(fs.RelName(destFileName, imp.originalsPath())))
}
if opt.Move {
if err := f.Move(destFileName); err != nil {
logRelName := txt.Quote(fs.RelName(destMainFileName, imp.originalsPath()))
logRelName := txt.LogParam(fs.RelName(destMainFileName, imp.originalsPath()))
log.Debugf("import: %s", err.Error())
log.Warnf("import: failed moving file to %s, is another import running at the same time?", logRelName)
}
} else {
if err := f.Copy(destFileName); err != nil {
logRelName := txt.Quote(fs.RelName(destMainFileName, imp.originalsPath()))
logRelName := txt.LogParam(fs.RelName(destMainFileName, imp.originalsPath()))
log.Debugf("import: %s", err.Error())
log.Warnf("import: failed copying file to %s, is another import running at the same time?", logRelName)
}
@@ -106,9 +106,9 @@ func ImportWorker(jobs <-chan ImportJob) {
// Remove duplicates to save storage.
if opt.RemoveExistingFiles {
if err := f.Remove(); err != nil {
log.Errorf("import: failed deleting %s (%s)", txt.Quote(f.BaseName()), err.Error())
log.Errorf("import: failed deleting %s (%s)", txt.LogParam(f.BaseName()), err.Error())
} else {
log.Infof("import: deleted %s (already exists)", txt.Quote(relFileName))
log.Infof("import: deleted %s (already exists)", txt.LogParam(relFileName))
}
}
}
@@ -118,13 +118,13 @@ func ImportWorker(jobs <-chan ImportJob) {
f, err := NewMediaFile(destMainFileName)
if err != nil {
log.Errorf("import: %s in %s", err.Error(), txt.Quote(fs.RelName(destMainFileName, imp.originalsPath())))
log.Errorf("import: %s in %s", err.Error(), txt.LogParam(fs.RelName(destMainFileName, imp.originalsPath())))
continue
}
if f.NeedsExifToolJson() {
if jsonName, err := imp.convert.ToJson(f); err != nil {
log.Debugf("import: %s in %s (extract metadata)", txt.Quote(err.Error()), txt.Quote(f.BaseName()))
log.Debugf("import: %s in %s (extract metadata)", txt.LogParam(err.Error()), txt.LogParam(f.BaseName()))
} else {
log.Debugf("import: created %s", filepath.Base(jsonName))
}
@@ -132,10 +132,10 @@ func ImportWorker(jobs <-chan ImportJob) {
if indexOpt.Convert && f.IsMedia() && !f.HasJpeg() {
if jpegFile, err := imp.convert.ToJpeg(f); err != nil {
log.Errorf("import: %s in %s (convert to jpeg)", err.Error(), txt.Quote(fs.RelName(destMainFileName, imp.originalsPath())))
log.Errorf("import: %s in %s (convert to jpeg)", err.Error(), txt.LogParam(fs.RelName(destMainFileName, imp.originalsPath())))
continue
} else {
log.Debugf("import: created %s", txt.Quote(jpegFile.BaseName()))
log.Debugf("import: created %s", txt.LogParam(jpegFile.BaseName()))
}
}
@@ -143,7 +143,7 @@ func ImportWorker(jobs <-chan ImportJob) {
log.Error(err)
} else {
if err := jpg.ResampleDefault(imp.thumbPath(), false); err != nil {
log.Errorf("import: %s in %s (resample)", err.Error(), txt.Quote(jpg.BaseName()))
log.Errorf("import: %s in %s (resample)", err.Error(), txt.LogParam(jpg.BaseName()))
continue
}
}
@@ -151,7 +151,7 @@ func ImportWorker(jobs <-chan ImportJob) {
related, err := f.RelatedFiles(imp.conf.Settings().StackSequences())
if err != nil {
log.Errorf("import: %s in %s (find related files)", err.Error(), txt.Quote(fs.RelName(destMainFileName, imp.originalsPath())))
log.Errorf("import: %s in %s (find related files)", err.Error(), txt.LogParam(fs.RelName(destMainFileName, imp.originalsPath())))
continue
}
@@ -165,13 +165,13 @@ func ImportWorker(jobs <-chan ImportJob) {
// Enforce file size limit for originals.
if sizeLimit > 0 && f.FileSize() > sizeLimit {
log.Warnf("import: %s exceeds file size limit (%d / %d MB)", txt.Quote(f.BaseName()), f.FileSize()/(1024*1024), sizeLimit/(1024*1024))
log.Warnf("import: %s exceeds file size limit (%d / %d MB)", txt.LogParam(f.BaseName()), f.FileSize()/(1024*1024), sizeLimit/(1024*1024))
continue
}
res := ind.MediaFile(f, indexOpt, originalName)
log.Infof("import: %s main %s file %s", res, f.FileType(), txt.Quote(f.RelName(ind.originalsPath())))
log.Infof("import: %s main %s file %s", res, f.FileType(), txt.LogParam(f.RelName(ind.originalsPath())))
done[f.FileName()] = true
if res.Success() {
@@ -198,13 +198,13 @@ func ImportWorker(jobs <-chan ImportJob) {
// Enforce file size limit for originals.
if sizeLimit > 0 && f.FileSize() > sizeLimit {
log.Warnf("import: %s exceeds file size limit (%d / %d MB)", txt.Quote(f.BaseName()), f.FileSize()/(1024*1024), sizeLimit/(1024*1024))
log.Warnf("import: %s exceeds file size limit (%d / %d MB)", txt.LogParam(f.BaseName()), f.FileSize()/(1024*1024), sizeLimit/(1024*1024))
continue
}
if f.NeedsExifToolJson() {
if jsonName, err := imp.convert.ToJson(f); err != nil {
log.Debugf("import: %s in %s (extract metadata)", txt.Quote(err.Error()), txt.Quote(f.BaseName()))
log.Debugf("import: %s in %s (extract metadata)", txt.LogParam(err.Error()), txt.LogParam(f.BaseName()))
} else {
log.Debugf("import: created %s", filepath.Base(jsonName))
}
@@ -214,12 +214,12 @@ func ImportWorker(jobs <-chan ImportJob) {
if res.Indexed() && f.IsJpeg() {
if err := f.ResampleDefault(ind.thumbPath(), false); err != nil {
log.Errorf("import: failed creating thumbnails for %s (%s)", txt.Quote(f.BaseName()), err.Error())
log.Errorf("import: failed creating thumbnails for %s (%s)", txt.LogParam(f.BaseName()), err.Error())
query.SetFileError(res.FileUID, err.Error())
}
}
log.Infof("import: %s related %s file %s", res, f.FileType(), txt.Quote(f.RelName(ind.originalsPath())))
log.Infof("import: %s related %s file %s", res, f.FileType(), txt.LogParam(f.RelName(ind.originalsPath())))
}
}

View File

@@ -89,7 +89,7 @@ func (ind *Index) Start(opt IndexOptions) fs.Done {
optionsPath := filepath.Join(originalsPath, opt.Path)
if !fs.PathExists(optionsPath) {
event.Error(fmt.Sprintf("index: %s does not exist", txt.Quote(optionsPath)))
event.Error(fmt.Sprintf("index: %s does not exist", txt.LogParam(optionsPath)))
return done
}
@@ -182,7 +182,7 @@ func (ind *Index) Start(opt IndexOptions) fs.Done {
}
if mf.FileSize() == 0 {
log.Infof("index: skipped empty file %s", txt.Quote(mf.BaseName()))
log.Infof("index: skipped empty file %s", txt.LogParam(mf.BaseName()))
return nil
}

View File

@@ -29,12 +29,12 @@ func (ind *Index) Faces(jpeg *MediaFile, expected int) face.Faces {
thumbName, err := jpeg.Thumbnail(Config().ThumbPath(), thumbSize)
if err != nil {
log.Debugf("index: %s in %s (faces)", err, txt.Quote(jpeg.BaseName()))
log.Debugf("index: %s in %s (faces)", err, txt.LogParam(jpeg.BaseName()))
return face.Faces{}
}
if thumbName == "" {
log.Debugf("index: thumb %s not found in %s (faces)", thumbSize, txt.Quote(jpeg.BaseName()))
log.Debugf("index: thumb %s not found in %s (faces)", thumbSize, txt.LogParam(jpeg.BaseName()))
return face.Faces{}
}
@@ -43,11 +43,11 @@ func (ind *Index) Faces(jpeg *MediaFile, expected int) face.Faces {
faces, err := ind.faceNet.Detect(thumbName, Config().FaceSize(), true, expected)
if err != nil {
log.Debugf("%s in %s", err, txt.Quote(jpeg.BaseName()))
log.Debugf("%s in %s", err, txt.LogParam(jpeg.BaseName()))
}
if l := len(faces); l > 0 {
log.Infof("index: found %s in %s [%s]", english.Plural(l, "face", "faces"), txt.Quote(jpeg.BaseName()), time.Since(start))
log.Infof("index: found %s in %s [%s]", english.Plural(l, "face", "faces"), txt.LogParam(jpeg.BaseName()), time.Since(start))
}
return faces

View File

@@ -28,14 +28,14 @@ func (ind *Index) Labels(jpeg *MediaFile) (results classify.Labels) {
filename, err := jpeg.Thumbnail(Config().ThumbPath(), size)
if err != nil {
log.Debugf("%s in %s", err, txt.Quote(jpeg.BaseName()))
log.Debugf("%s in %s", err, txt.LogParam(jpeg.BaseName()))
continue
}
imageLabels, err := ind.tensorFlow.File(filename)
if err != nil {
log.Debugf("%s in %s", err, txt.Quote(jpeg.BaseName()))
log.Debugf("%s in %s", err, txt.LogParam(jpeg.BaseName()))
continue
}
@@ -58,9 +58,9 @@ func (ind *Index) Labels(jpeg *MediaFile) (results classify.Labels) {
}
if l := len(labels); l == 1 {
log.Infof("index: matched %d label with %s [%s]", l, txt.Quote(jpeg.BaseName()), time.Since(start))
log.Infof("index: matched %d label with %s [%s]", l, txt.LogParam(jpeg.BaseName()), time.Since(start))
} else if l > 1 {
log.Infof("index: matched %d labels with %s [%s]", l, txt.Quote(jpeg.BaseName()), time.Since(start))
log.Infof("index: matched %d labels with %s [%s]", l, txt.LogParam(jpeg.BaseName()), time.Since(start))
}
return results

View File

@@ -54,7 +54,7 @@ func (ind *Index) MediaFile(m *MediaFile, o IndexOptions, originalName string) (
fileRoot, fileBase, filePath, fileName := m.PathNameInfo(stripSequence)
fullBase := m.BasePrefix(false)
logName := txt.Quote(fileName)
logName := txt.LogParam(fileName)
fileSize, modTime, err := m.Stat()
if err != nil {
@@ -160,13 +160,13 @@ func (ind *Index) MediaFile(m *MediaFile, o IndexOptions, originalName string) (
if fileRenamed {
fileChanged = true
log.Debugf("index: %s was renamed", txt.Quote(m.BaseName()))
log.Debugf("index: %s was renamed", txt.LogParam(m.BaseName()))
} else if file.Changed(fileSize, modTime) {
fileChanged = true
log.Debugf("index: %s was modified (new size %d, old size %d, new timestamp %d, old timestamp %d)", txt.Quote(m.BaseName()), fileSize, file.FileSize, modTime.Unix(), file.ModTime)
log.Debugf("index: %s was modified (new size %d, old size %d, new timestamp %d, old timestamp %d)", txt.LogParam(m.BaseName()), fileSize, file.FileSize, modTime.Unix(), file.ModTime)
} else if file.Missing() {
fileChanged = true
log.Debugf("index: %s was missing", txt.Quote(m.BaseName()))
log.Debugf("index: %s was missing", txt.LogParam(m.BaseName()))
}
}
@@ -196,10 +196,10 @@ func (ind *Index) MediaFile(m *MediaFile, o IndexOptions, originalName string) (
if err := photo.LoadFromYaml(yamlName); err != nil {
log.Errorf("index: %s in %s (restore from yaml)", err.Error(), logName)
} else if err := photo.Find(); err != nil {
log.Infof("index: %s restored from %s", txt.Quote(m.BaseName()), txt.Quote(filepath.Base(yamlName)))
log.Infof("index: %s restored from %s", txt.LogParam(m.BaseName()), txt.LogParam(filepath.Base(yamlName)))
} else {
photoExists = true
log.Infof("index: uid %s restored from %s", photo.PhotoUID, txt.Quote(filepath.Base(yamlName)))
log.Infof("index: uid %s restored from %s", photo.PhotoUID, txt.LogParam(filepath.Base(yamlName)))
}
}
}
@@ -332,7 +332,7 @@ func (ind *Index) MediaFile(m *MediaFile, o IndexOptions, originalName string) (
file.SetColorProfile(metaData.ColorProfile)
if metaData.HasInstanceID() {
log.Infof("index: %s has instance_id %s", logName, txt.Quote(metaData.InstanceID))
log.Infof("index: %s has instance_id %s", logName, txt.LogParam(metaData.InstanceID))
file.InstanceID = metaData.InstanceID
}
@@ -371,13 +371,13 @@ func (ind *Index) MediaFile(m *MediaFile, o IndexOptions, originalName string) (
details.SetCopyright(metaData.Copyright, entity.SrcMeta)
if metaData.HasDocumentID() && photo.UUID == "" {
log.Infof("index: %s has document_id %s", logName, txt.Quote(metaData.DocumentID))
log.Infof("index: %s has document_id %s", logName, txt.LogParam(metaData.DocumentID))
photo.UUID = metaData.DocumentID
}
if metaData.HasInstanceID() {
log.Infof("index: %s has instance_id %s", logName, txt.Quote(metaData.InstanceID))
log.Infof("index: %s has instance_id %s", logName, txt.LogParam(metaData.InstanceID))
file.InstanceID = metaData.InstanceID
}
@@ -421,13 +421,13 @@ func (ind *Index) MediaFile(m *MediaFile, o IndexOptions, originalName string) (
details.SetCopyright(metaData.Copyright, entity.SrcMeta)
if metaData.HasDocumentID() && photo.UUID == "" {
log.Infof("index: %s has document_id %s", logName, txt.Quote(metaData.DocumentID))
log.Infof("index: %s has document_id %s", logName, txt.LogParam(metaData.DocumentID))
photo.UUID = metaData.DocumentID
}
if metaData.HasInstanceID() {
log.Infof("index: %s has instance_id %s", logName, txt.Quote(metaData.InstanceID))
log.Infof("index: %s has instance_id %s", logName, txt.LogParam(metaData.InstanceID))
file.InstanceID = metaData.InstanceID
}
@@ -526,7 +526,7 @@ func (ind *Index) MediaFile(m *MediaFile, o IndexOptions, originalName string) (
details.SetCopyright(metaData.Copyright, entity.SrcMeta)
if metaData.HasDocumentID() && photo.UUID == "" {
log.Debugf("index: %s has document_id %s", logName, txt.Quote(metaData.DocumentID))
log.Debugf("index: %s has document_id %s", logName, txt.LogParam(metaData.DocumentID))
photo.UUID = metaData.DocumentID
}
@@ -745,7 +745,7 @@ func (ind *Index) MediaFile(m *MediaFile, o IndexOptions, originalName string) (
if err := photo.SaveAsYaml(yamlFile); err != nil {
log.Errorf("index: %s in %s (update yaml)", err.Error(), logName)
} else {
log.Debugf("index: updated yaml file %s", txt.Quote(filepath.Base(yamlFile)))
log.Debugf("index: updated yaml file %s", txt.LogParam(filepath.Base(yamlFile)))
}
}

View File

@@ -20,7 +20,7 @@ func (ind *Index) NSFW(jpeg *MediaFile) bool {
return false
} else {
if nsfwLabels.NSFW(nsfw.ThresholdHigh) {
log.Warnf("index: %s might contain offensive content", txt.Quote(jpeg.RelName(Config().OriginalsPath())))
log.Warnf("index: %s might contain offensive content", txt.LogParam(jpeg.RelName(Config().OriginalsPath())))
return true
}
}

View File

@@ -12,7 +12,7 @@ import (
func IndexMain(related *RelatedFiles, ind *Index, opt IndexOptions) (result IndexResult) {
// Skip sidecar files without related media file.
if related.Main == nil {
result.Err = fmt.Errorf("index: found no main file for %s", txt.Quote(related.String()))
result.Err = fmt.Errorf("index: found no main file for %s", txt.LogParam(related.String()))
result.Status = IndexFailed
return result
}
@@ -22,14 +22,14 @@ func IndexMain(related *RelatedFiles, ind *Index, opt IndexOptions) (result Inde
// Enforce file size limit for originals.
if sizeLimit > 0 && f.FileSize() > sizeLimit {
result.Err = fmt.Errorf("index: %s exceeds file size limit (%d / %d MB)", txt.Quote(f.BaseName()), f.FileSize()/(1024*1024), sizeLimit/(1024*1024))
result.Err = fmt.Errorf("index: %s exceeds file size limit (%d / %d MB)", txt.LogParam(f.BaseName()), f.FileSize()/(1024*1024), sizeLimit/(1024*1024))
result.Status = IndexFailed
return result
}
if f.NeedsExifToolJson() {
if jsonName, err := ind.convert.ToJson(f); err != nil {
log.Debugf("index: %s in %s (extract metadata)", txt.Quote(err.Error()), txt.Quote(f.BaseName()))
log.Debugf("index: %s in %s (extract metadata)", txt.LogParam(err.Error()), txt.LogParam(f.BaseName()))
} else {
log.Debugf("index: created %s", filepath.Base(jsonName))
}
@@ -37,15 +37,15 @@ func IndexMain(related *RelatedFiles, ind *Index, opt IndexOptions) (result Inde
if opt.Convert && f.IsMedia() && !f.HasJpeg() {
if jpegFile, err := ind.convert.ToJpeg(f); err != nil {
result.Err = fmt.Errorf("index: failed converting %s to jpeg (%s)", txt.Quote(f.BaseName()), err.Error())
result.Err = fmt.Errorf("index: failed converting %s to jpeg (%s)", txt.LogParam(f.BaseName()), err.Error())
result.Status = IndexFailed
return result
} else {
log.Debugf("index: created %s", txt.Quote(jpegFile.BaseName()))
log.Debugf("index: created %s", txt.LogParam(jpegFile.BaseName()))
if err := jpegFile.ResampleDefault(ind.thumbPath(), false); err != nil {
result.Err = fmt.Errorf("index: failed creating thumbnails for %s (%s)", txt.Quote(f.BaseName()), err.Error())
result.Err = fmt.Errorf("index: failed creating thumbnails for %s (%s)", txt.LogParam(f.BaseName()), err.Error())
result.Status = IndexFailed
return result
@@ -59,12 +59,12 @@ func IndexMain(related *RelatedFiles, ind *Index, opt IndexOptions) (result Inde
if result.Indexed() && f.IsJpeg() {
if err := f.ResampleDefault(ind.thumbPath(), false); err != nil {
log.Errorf("index: failed creating thumbnails for %s (%s)", txt.Quote(f.BaseName()), err.Error())
log.Errorf("index: failed creating thumbnails for %s (%s)", txt.LogParam(f.BaseName()), err.Error())
query.SetFileError(result.FileUID, err.Error())
}
}
log.Infof("index: %s main %s file %s", result, f.FileType(), txt.Quote(f.RelName(ind.originalsPath())))
log.Infof("index: %s main %s file %s", result, f.FileType(), txt.LogParam(f.RelName(ind.originalsPath())))
return result
}
@@ -104,13 +104,13 @@ func IndexRelated(related RelatedFiles, ind *Index, opt IndexOptions) (result In
// Enforce file size limit for originals.
if sizeLimit > 0 && f.FileSize() > sizeLimit {
log.Warnf("index: %s exceeds file size limit (%d / %d MB)", txt.Quote(f.BaseName()), f.FileSize()/(1024*1024), sizeLimit/(1024*1024))
log.Warnf("index: %s exceeds file size limit (%d / %d MB)", txt.LogParam(f.BaseName()), f.FileSize()/(1024*1024), sizeLimit/(1024*1024))
continue
}
if f.NeedsExifToolJson() {
if jsonName, err := ind.convert.ToJson(f); err != nil {
log.Debugf("index: %s in %s (extract metadata)", txt.Quote(err.Error()), txt.Quote(f.BaseName()))
log.Debugf("index: %s in %s (extract metadata)", txt.LogParam(err.Error()), txt.LogParam(f.BaseName()))
} else {
log.Debugf("index: created %s", filepath.Base(jsonName))
}
@@ -118,15 +118,15 @@ func IndexRelated(related RelatedFiles, ind *Index, opt IndexOptions) (result In
if opt.Convert && f.IsMedia() && !f.HasJpeg() {
if jpegFile, err := ind.convert.ToJpeg(f); err != nil {
result.Err = fmt.Errorf("index: failed converting %s to jpeg (%s)", txt.Quote(f.BaseName()), err.Error())
result.Err = fmt.Errorf("index: failed converting %s to jpeg (%s)", txt.LogParam(f.BaseName()), err.Error())
result.Status = IndexFailed
return result
} else {
log.Debugf("index: created %s", txt.Quote(jpegFile.BaseName()))
log.Debugf("index: created %s", txt.LogParam(jpegFile.BaseName()))
if err := jpegFile.ResampleDefault(ind.thumbPath(), false); err != nil {
result.Err = fmt.Errorf("index: failed creating thumbnails for %s (%s)", txt.Quote(f.BaseName()), err.Error())
result.Err = fmt.Errorf("index: failed creating thumbnails for %s (%s)", txt.LogParam(f.BaseName()), err.Error())
result.Status = IndexFailed
return result
@@ -140,12 +140,12 @@ func IndexRelated(related RelatedFiles, ind *Index, opt IndexOptions) (result In
if res.Indexed() && f.IsJpeg() {
if err := f.ResampleDefault(ind.thumbPath(), false); err != nil {
log.Errorf("index: failed creating thumbnails for %s (%s)", txt.Quote(f.BaseName()), err.Error())
log.Errorf("index: failed creating thumbnails for %s (%s)", txt.LogParam(f.BaseName()), err.Error())
query.SetFileError(res.FileUID, err.Error())
}
}
log.Infof("index: %s related %s file %s", res, f.FileType(), txt.Quote(f.BaseName()))
log.Infof("index: %s related %s file %s", res, f.FileType(), txt.LogParam(f.BaseName()))
}
return result

View File

@@ -60,7 +60,7 @@ func NewMediaFile(fileName string) (*MediaFile, error) {
}
if _, _, err := m.Stat(); err != nil {
return m, fmt.Errorf("media: %s not found", txt.Quote(m.BaseName()))
return m, fmt.Errorf("media: %s not found", txt.LogParam(m.BaseName()))
}
return m, nil
@@ -300,12 +300,12 @@ func (m *MediaFile) RelatedFiles(stripSequence bool) (result RelatedFiles, err e
f, err := NewMediaFile(fileName)
if err != nil {
log.Warnf("media: %s in %s", err, txt.Quote(filepath.Base(fileName)))
log.Warnf("media: %s in %s", err, txt.LogParam(filepath.Base(fileName)))
continue
}
if f.FileSize() == 0 {
log.Warnf("media: %s is empty", txt.Quote(filepath.Base(fileName)))
log.Warnf("media: %s is empty", txt.LogParam(filepath.Base(fileName)))
continue
}
@@ -335,7 +335,7 @@ func (m *MediaFile) RelatedFiles(stripSequence bool) (result RelatedFiles, err e
t = "unknown type"
}
return result, fmt.Errorf("no supported files found for %s (%s)", txt.Quote(m.BaseName()), t)
return result, fmt.Errorf("no supported files found for %s (%s)", txt.LogParam(m.BaseName()), t)
}
// Add hidden JPEG if exists.
@@ -789,7 +789,7 @@ func (m *MediaFile) HasJpeg() bool {
func (m *MediaFile) decodeDimensions() error {
if !m.IsMedia() {
return fmt.Errorf("failed decoding dimensions for %s", txt.Quote(m.BaseName()))
return fmt.Errorf("failed decoding dimensions for %s", txt.LogParam(m.BaseName()))
}
if m.IsJpeg() || m.IsPng() || m.IsGif() {
@@ -901,7 +901,7 @@ func (m *MediaFile) Thumbnail(path string, sizeName thumb.Name) (filename string
thumbnail, err := thumb.FromFile(m.FileName(), m.Hash(), path, size.Width, size.Height, m.Orientation(), size.Options...)
if err != nil {
err = fmt.Errorf("media: failed creating thumbnail for %s (%s)", txt.Quote(m.BaseName()), err)
err = fmt.Errorf("media: failed creating thumbnail for %s (%s)", txt.LogParam(m.BaseName()), err)
log.Debug(err)
return "", err
}
@@ -949,7 +949,7 @@ func (m *MediaFile) ResampleDefault(thumbPath string, force bool) (err error) {
}
if fileName, err := thumb.FileName(hash, thumbPath, size.Width, size.Height, size.Options...); err != nil {
log.Errorf("media: failed creating %s (%s)", txt.Quote(string(name)), err)
log.Errorf("media: failed creating %s (%s)", txt.LogParam(string(name)), err)
return err
} else {
@@ -961,7 +961,7 @@ func (m *MediaFile) ResampleDefault(thumbPath string, force bool) (err error) {
img, err := thumb.Open(m.FileName(), m.Orientation())
if err != nil {
log.Debugf("media: %s in %s", err.Error(), txt.Quote(m.BaseName()))
log.Debugf("media: %s in %s", err.Error(), txt.LogParam(m.BaseName()))
return err
}
@@ -980,7 +980,7 @@ func (m *MediaFile) ResampleDefault(thumbPath string, force bool) (err error) {
}
if err != nil {
log.Errorf("media: failed creating %s (%s)", txt.Quote(string(name)), err)
log.Errorf("media: failed creating %s (%s)", txt.LogParam(string(name)), err)
return err
}
@@ -1015,9 +1015,9 @@ func (m *MediaFile) RenameSidecars(oldFileName string) (renamed map[string]strin
renamed[fs.RelName(srcName, sidecarPath)] = fs.RelName(destName, sidecarPath)
if err := os.Remove(srcName); err != nil {
log.Errorf("media: failed removing sidecar %s", txt.Quote(fs.RelName(srcName, sidecarPath)))
log.Errorf("media: failed removing sidecar %s", txt.LogParam(fs.RelName(srcName, sidecarPath)))
} else {
log.Infof("media: removed sidecar %s", txt.Quote(fs.RelName(srcName, sidecarPath)))
log.Infof("media: removed sidecar %s", txt.LogParam(fs.RelName(srcName, sidecarPath)))
}
continue
@@ -1026,7 +1026,7 @@ func (m *MediaFile) RenameSidecars(oldFileName string) (renamed map[string]strin
if err := fs.Move(srcName, destName); err != nil {
return renamed, err
} else {
log.Infof("media: moved existing sidecar to %s", txt.Quote(newName+filepath.Ext(srcName)))
log.Infof("media: moved existing sidecar to %s", txt.LogParam(newName+filepath.Ext(srcName)))
renamed[fs.RelName(srcName, sidecarPath)] = fs.RelName(destName, sidecarPath)
}
}
@@ -1051,9 +1051,9 @@ func (m *MediaFile) RemoveSidecars() (err error) {
for _, sidecarName := range matches {
if err = os.Remove(sidecarName); err != nil {
log.Errorf("media: failed removing sidecar %s", txt.Quote(fs.RelName(sidecarName, sidecarPath)))
log.Errorf("media: failed removing sidecar %s", txt.LogParam(fs.RelName(sidecarName, sidecarPath)))
} else {
log.Infof("media: removed sidecar %s", txt.Quote(fs.RelName(sidecarName, sidecarPath)))
log.Infof("media: removed sidecar %s", txt.LogParam(fs.RelName(sidecarName, sidecarPath)))
}
}

View File

@@ -80,7 +80,7 @@ func (m *MediaFile) MetaData() (result meta.Data) {
// Parse regular JSON sidecar files ("img_1234.json")
if !m.IsSidecar() {
if jsonFiles := fs.FormatJson.FindAll(m.FileName(), []string{Config().SidecarPath(), fs.HiddenPath}, Config().OriginalsPath(), false); len(jsonFiles) == 0 {
log.Tracef("metadata: found no additional sidecar file for %s", txt.Quote(filepath.Base(m.FileName())))
log.Tracef("metadata: found no additional sidecar file for %s", txt.LogParam(filepath.Base(m.FileName())))
} else {
for _, jsonFile := range jsonFiles {
jsonErr := m.metaData.JSON(jsonFile, m.BaseName())
@@ -102,7 +102,7 @@ func (m *MediaFile) MetaData() (result meta.Data) {
if err != nil {
m.metaData.Error = err
log.Debugf("metadata: %s in %s", err, txt.Quote(m.BaseName()))
log.Debugf("metadata: %s in %s", err, txt.LogParam(m.BaseName()))
}
})

View File

@@ -95,11 +95,11 @@ func (w *Moments) Start() (err error) {
if a := entity.FindFolderAlbum(mom.Path); a != nil {
if a.DeletedAt != nil {
// Nothing to do.
log.Tracef("moments: %s was deleted (%s)", txt.Quote(a.AlbumTitle), a.AlbumFilter)
log.Tracef("moments: %s was deleted (%s)", txt.LogParam(a.AlbumTitle), a.AlbumFilter)
} else if err := a.UpdateFolder(mom.Path, f.Serialize()); err != nil {
log.Errorf("moments: %s (update folder)", err.Error())
} else {
log.Tracef("moments: %s already exists (%s)", txt.Quote(a.AlbumTitle), a.AlbumFilter)
log.Tracef("moments: %s already exists (%s)", txt.LogParam(a.AlbumTitle), a.AlbumFilter)
}
} else if a := entity.NewFolderAlbum(mom.Title(), mom.Path, f.Serialize()); a != nil {
a.AlbumYear = mom.FolderYear
@@ -110,7 +110,7 @@ func (w *Moments) Start() (err error) {
if err := a.Create(); err != nil {
log.Errorf("moments: %s (create folder)", err)
} else {
log.Infof("moments: added %s (%s)", txt.Quote(a.AlbumTitle), a.AlbumFilter)
log.Infof("moments: added %s (%s)", txt.LogParam(a.AlbumTitle), a.AlbumFilter)
}
}
}
@@ -127,17 +127,17 @@ func (w *Moments) Start() (err error) {
}
if !a.Deleted() {
log.Tracef("moments: %s already exists (%s)", txt.Quote(a.AlbumTitle), a.AlbumFilter)
log.Tracef("moments: %s already exists (%s)", txt.LogParam(a.AlbumTitle), a.AlbumFilter)
} else if err := a.Restore(); err != nil {
log.Errorf("moments: %s (restore month)", err.Error())
} else {
log.Infof("moments: %s restored", txt.Quote(a.AlbumTitle))
log.Infof("moments: %s restored", txt.LogParam(a.AlbumTitle))
}
} else if a := entity.NewMonthAlbum(mom.Title(), mom.Slug(), mom.Year, mom.Month); a != nil {
if err := a.Create(); err != nil {
log.Errorf("moments: %s", err)
} else {
log.Infof("moments: added %s (%s)", txt.Quote(a.AlbumTitle), a.AlbumFilter)
log.Infof("moments: added %s (%s)", txt.LogParam(a.AlbumTitle), a.AlbumFilter)
}
}
}
@@ -161,9 +161,9 @@ func (w *Moments) Start() (err error) {
if a.DeletedAt != nil {
// Nothing to do.
log.Tracef("moments: %s was deleted (%s)", txt.Quote(a.AlbumTitle), a.AlbumFilter)
log.Tracef("moments: %s was deleted (%s)", txt.LogParam(a.AlbumTitle), a.AlbumFilter)
} else {
log.Tracef("moments: %s already exists (%s)", txt.Quote(a.AlbumTitle), a.AlbumFilter)
log.Tracef("moments: %s already exists (%s)", txt.LogParam(a.AlbumTitle), a.AlbumFilter)
}
} else if a := entity.NewMomentsAlbum(mom.Title(), mom.Slug(), f.Serialize()); a != nil {
a.AlbumYear = mom.Year
@@ -172,7 +172,7 @@ func (w *Moments) Start() (err error) {
if err := a.Create(); err != nil {
log.Errorf("moments: %s", err)
} else {
log.Infof("moments: added %s (%s)", txt.Quote(a.AlbumTitle), a.AlbumFilter)
log.Infof("moments: added %s (%s)", txt.LogParam(a.AlbumTitle), a.AlbumFilter)
}
}
}
@@ -195,11 +195,11 @@ func (w *Moments) Start() (err error) {
}
if !a.Deleted() {
log.Tracef("moments: %s already exists (%s)", txt.Quote(a.AlbumTitle), a.AlbumFilter)
log.Tracef("moments: %s already exists (%s)", txt.LogParam(a.AlbumTitle), a.AlbumFilter)
} else if err := a.Restore(); err != nil {
log.Errorf("moments: %s (restore state)", err.Error())
} else {
log.Infof("moments: %s restored", txt.Quote(a.AlbumTitle))
log.Infof("moments: %s restored", txt.LogParam(a.AlbumTitle))
}
} else if a := entity.NewStateAlbum(mom.Title(), mom.Slug(), f.Serialize()); a != nil {
a.AlbumLocation = mom.CountryName()
@@ -209,7 +209,7 @@ func (w *Moments) Start() (err error) {
if err := a.Create(); err != nil {
log.Errorf("moments: %s", err)
} else {
log.Infof("moments: added %s (%s)", txt.Quote(a.AlbumTitle), a.AlbumFilter)
log.Infof("moments: added %s (%s)", txt.LogParam(a.AlbumTitle), a.AlbumFilter)
}
}
}
@@ -233,20 +233,20 @@ func (w *Moments) Start() (err error) {
}
if a.DeletedAt != nil || f.Serialize() == a.AlbumFilter {
log.Tracef("moments: %s already exists (%s)", txt.Quote(a.AlbumTitle), a.AlbumFilter)
log.Tracef("moments: %s already exists (%s)", txt.LogParam(a.AlbumTitle), a.AlbumFilter)
continue
}
if err := a.Update("AlbumFilter", f.Serialize()); err != nil {
log.Errorf("moments: %s", err.Error())
} else {
log.Debugf("moments: updated %s (%s)", txt.Quote(a.AlbumTitle), f.Serialize())
log.Debugf("moments: updated %s (%s)", txt.LogParam(a.AlbumTitle), f.Serialize())
}
} else if a := entity.NewMomentsAlbum(mom.Title(), mom.Slug(), f.Serialize()); a != nil {
if err := a.Create(); err != nil {
log.Errorf("moments: %s", err.Error())
} else {
log.Infof("moments: added %s (%s)", txt.Quote(a.AlbumTitle), a.AlbumFilter)
log.Infof("moments: added %s (%s)", txt.LogParam(a.AlbumTitle), a.AlbumFilter)
}
} else {
log.Errorf("moments: failed to create new moment %s (%s)", mom.Title(), f.Serialize())

View File

@@ -87,20 +87,20 @@ func (w *Purge) Start(opt PurgeOptions) (purgedFiles map[string]bool, purgedPhot
if file.FileMissing {
if fs.FileExists(fileName) {
if opt.Dry {
log.Infof("purge: found %s", txt.Quote(file.FileName))
log.Infof("purge: found %s", txt.LogParam(file.FileName))
continue
}
if err := file.Found(); err != nil {
log.Errorf("purge: %s", err)
} else {
log.Infof("purge: found %s", txt.Quote(file.FileName))
log.Infof("purge: found %s", txt.LogParam(file.FileName))
}
}
} else if !fs.FileExists(fileName) {
if opt.Dry {
purgedFiles[fileName] = true
log.Infof("purge: file %s would be flagged as missing", txt.Quote(file.FileName))
log.Infof("purge: file %s would be flagged as missing", txt.LogParam(file.FileName))
continue
}
@@ -113,7 +113,7 @@ func (w *Purge) Start(opt PurgeOptions) (purgedFiles map[string]bool, purgedPhot
w.files.Remove(file.FileName, file.FileRoot)
purgedFiles[fileName] = true
log.Infof("purge: flagged file %s as missing", txt.Quote(file.FileName))
log.Infof("purge: flagged file %s as missing", txt.LogParam(file.FileName))
if !wasPrimary {
continue
@@ -162,7 +162,7 @@ func (w *Purge) Start(opt PurgeOptions) (purgedFiles map[string]bool, purgedPhot
if !fs.FileExists(fileName) {
if opt.Dry {
purgedFiles[fileName] = true
log.Infof("purge: duplicate %s would be removed", txt.Quote(file.FileName))
log.Infof("purge: duplicate %s would be removed", txt.LogParam(file.FileName))
continue
}
@@ -171,7 +171,7 @@ func (w *Purge) Start(opt PurgeOptions) (purgedFiles map[string]bool, purgedPhot
} else {
w.files.Remove(file.FileName, file.FileRoot)
purgedFiles[fileName] = true
log.Infof("purge: removed duplicate %s", txt.Quote(file.FileName))
log.Infof("purge: removed duplicate %s", txt.LogParam(file.FileName))
}
}
}
@@ -210,7 +210,7 @@ func (w *Purge) Start(opt PurgeOptions) (purgedFiles map[string]bool, purgedPhot
if opt.Dry {
purgedPhotos[photo.PhotoUID] = true
log.Infof("purge: %s would be removed", txt.Quote(photo.PhotoName))
log.Infof("purge: %s would be removed", txt.LogParam(photo.PhotoName))
continue
}
@@ -220,9 +220,9 @@ func (w *Purge) Start(opt PurgeOptions) (purgedFiles map[string]bool, purgedPhot
purgedPhotos[photo.PhotoUID] = true
if opt.Hard {
log.Infof("purge: permanently removed %s", txt.Quote(photo.PhotoName))
log.Infof("purge: permanently removed %s", txt.LogParam(photo.PhotoName))
} else {
log.Infof("purge: flagged photo %s as deleted", txt.Quote(photo.PhotoName))
log.Infof("purge: flagged photo %s as deleted", txt.LogParam(photo.PhotoName))
}
// Remove files from lookup table.

View File

@@ -52,7 +52,7 @@ func AlbumCoverByUID(uid string) (file entity.File, err error) {
if err := a.Delete(); err != nil {
log.Errorf("%s: %s (hide)", a.AlbumType, err)
} else {
log.Infof("%s: %s hidden", a.AlbumType, txt.Quote(a.AlbumTitle))
log.Infof("%s: %s hidden", a.AlbumType, txt.LogParam(a.AlbumTitle))
}
}

View File

@@ -138,15 +138,15 @@ func MergeFaces(merge entity.Faces) (merged *entity.Face, err error) {
for i := 1; i < len(merge); i++ {
if merge[i].SubjUID != subjUID {
return merged, fmt.Errorf("faces: can't merge clusters with conflicting subjects %s <> %s",
txt.Quote(subjUID), txt.Quote(merge[i].SubjUID))
txt.LogParam(subjUID), txt.LogParam(merge[i].SubjUID))
}
}
// Find or create merged face cluster.
if merged = entity.NewFace(merge[0].SubjUID, merge[0].FaceSrc, merge.Embeddings()); merged == nil {
return merged, fmt.Errorf("faces: new cluster is nil for subject %s", txt.Quote(subjUID))
return merged, fmt.Errorf("faces: new cluster is nil for subject %s", txt.LogParam(subjUID))
} else if merged = entity.FirstOrCreateFace(merged); merged == nil {
return merged, fmt.Errorf("faces: failed creating new cluster for subject %s", txt.Quote(subjUID))
return merged, fmt.Errorf("faces: failed creating new cluster for subject %s", txt.LogParam(subjUID))
} else if err := merged.MatchMarkers(append(merge.IDs(), "")); err != nil {
return merged, err
}
@@ -155,9 +155,9 @@ func MergeFaces(merge entity.Faces) (merged *entity.Face, err error) {
if removed, err := PurgeOrphanFaces(merge.IDs()); err != nil {
return merged, err
} else if removed > 0 {
log.Debugf("faces: removed %d orphans for subject %s", removed, txt.Quote(subjUID))
log.Debugf("faces: removed %d orphans for subject %s", removed, txt.LogParam(subjUID))
} else {
log.Warnf("faces: failed removing merged clusters for subject %s", txt.Quote(subjUID))
log.Warnf("faces: failed removing merged clusters for subject %s", txt.LogParam(subjUID))
}
return merged, err
@@ -185,13 +185,13 @@ func ResolveFaceCollisions() (conflicts, resolved int, err error) {
log.Infof("face %s: ambiguous subject at dist %f, Ø %f from %d samples, collision Ø %f", f1.ID, dist, r, f1.Samples, f1.CollisionRadius)
if f1.SubjUID != "" {
log.Debugf("face %s: subject %s (%s %s)", f1.ID, txt.Quote(f1.SubjUID), f1.SubjUID, entity.SrcString(f1.FaceSrc))
log.Debugf("face %s: subject %s (%s %s)", f1.ID, txt.LogParam(f1.SubjUID), f1.SubjUID, entity.SrcString(f1.FaceSrc))
} else {
log.Debugf("face %s: has no subject (%s)", f1.ID, entity.SrcString(f1.FaceSrc))
}
if f2.SubjUID != "" {
log.Debugf("face %s: subject %s (%s %s)", f2.ID, txt.Quote(f2.SubjUID), f2.SubjUID, entity.SrcString(f2.FaceSrc))
log.Debugf("face %s: subject %s (%s %s)", f2.ID, txt.LogParam(f2.SubjUID), f2.SubjUID, entity.SrcString(f2.FaceSrc))
} else {
log.Debugf("face %s: has no subject (%s)", f2.ID, entity.SrcString(f2.FaceSrc))
}

View File

@@ -94,10 +94,10 @@ func CreateMarkerSubjects() (affected int64, err error) {
if name == m.MarkerName && subj != nil {
// Do nothing.
} else if subj = entity.NewSubject(m.MarkerName, entity.SubjPerson, entity.SrcMarker); subj == nil {
log.Errorf("faces: invalid subject %s", txt.Quote(m.MarkerName))
log.Errorf("faces: invalid subject %s", txt.LogParam(m.MarkerName))
continue
} else if subj = entity.FirstOrCreateSubject(subj); subj == nil {
log.Errorf("faces: failed adding subject %s", txt.Quote(m.MarkerName))
log.Errorf("faces: failed adding subject %s", txt.LogParam(m.MarkerName))
continue
} else {
affected++

View File

@@ -104,7 +104,7 @@ func Geo(f form.SearchGeo) (results GeoResults, err error) {
var labelIds []uint
if err := Db().Where(AnySlug("custom_slug", f.Query, " ")).Find(&labels).Error; len(labels) == 0 || err != nil {
log.Debugf("search: label %s not found, using fuzzy search", txt.QuoteLower(f.Query))
log.Debugf("search: label %s not found, using fuzzy search", txt.LogParamLower(f.Query))
for _, where := range LikeAnyKeyword("k.keyword", f.Query) {
s = s.Where("photos.id IN (SELECT pk.photo_id FROM keywords k JOIN photos_keywords pk ON k.id = pk.keyword_id WHERE (?))", gorm.Expr(where))
@@ -115,7 +115,7 @@ func Geo(f form.SearchGeo) (results GeoResults, err error) {
Db().Where("category_id = ?", l.ID).Find(&categories)
log.Debugf("search: label %s includes %d categories", txt.QuoteLower(l.LabelName), len(categories))
log.Debugf("search: label %s includes %d categories", txt.LogParamLower(l.LabelName), len(categories))
for _, category := range categories {
labelIds = append(labelIds, category.LabelID)

View File

@@ -59,7 +59,7 @@ func Labels(f form.SearchLabels) (results []Label, err error) {
likeString := "%" + f.Query + "%"
if result := Db().First(&label, "label_slug = ? OR custom_slug = ?", slugString, slugString); result.Error != nil {
log.Infof("search: label %s not found", txt.Quote(f.Query))
log.Infof("search: label %s not found", txt.LogParam(f.Query))
s = s.Where("labels.label_name LIKE ?", likeString)
} else {
@@ -71,7 +71,7 @@ func Labels(f form.SearchLabels) (results []Label, err error) {
labelIds = append(labelIds, category.LabelID)
}
log.Infof("search: label %s includes %d categories", txt.Quote(label.LabelName), len(labelIds))
log.Infof("search: label %s includes %d categories", txt.LogParam(label.LabelName), len(labelIds))
s = s.Where("labels.id IN (?)", labelIds)
}

View File

@@ -116,7 +116,7 @@ func Photos(f form.SearchPhotos) (results PhotoResults, count int, err error) {
if f.Label != "" {
if err := Db().Where(AnySlug("label_slug", f.Label, txt.Or)).Or(AnySlug("custom_slug", f.Label, txt.Or)).Find(&labels).Error; len(labels) == 0 || err != nil {
log.Debugf("search: label %s not found", txt.QuoteLower(f.Label))
log.Debugf("search: label %s not found", txt.LogParamLower(f.Label))
return PhotoResults{}, 0, nil
} else {
for _, l := range labels {
@@ -124,7 +124,7 @@ func Photos(f form.SearchPhotos) (results PhotoResults, count int, err error) {
Db().Where("category_id = ?", l.ID).Find(&categories)
log.Infof("search: label %s includes %d categories", txt.QuoteLower(l.LabelName), len(categories))
log.Infof("search: label %s includes %d categories", txt.LogParamLower(l.LabelName), len(categories))
for _, category := range categories {
labelIds = append(labelIds, category.LabelID)
@@ -195,7 +195,7 @@ func Photos(f form.SearchPhotos) (results PhotoResults, count int, err error) {
}
} else if f.Query != "" {
if err := Db().Where(AnySlug("custom_slug", f.Query, " ")).Find(&labels).Error; len(labels) == 0 || err != nil {
log.Debugf("search: label %s not found, using fuzzy search", txt.QuoteLower(f.Query))
log.Debugf("search: label %s not found, using fuzzy search", txt.LogParamLower(f.Query))
for _, where := range LikeAnyKeyword("k.keyword", f.Query) {
s = s.Where("photos.id IN (SELECT pk.photo_id FROM keywords k JOIN photos_keywords pk ON k.id = pk.keyword_id WHERE (?))", gorm.Expr(where))
@@ -206,7 +206,7 @@ func Photos(f form.SearchPhotos) (results PhotoResults, count int, err error) {
Db().Where("category_id = ?", l.ID).Find(&categories)
log.Debugf("search: label %s includes %d categories", txt.QuoteLower(l.LabelName), len(categories))
log.Debugf("search: label %s includes %d categories", txt.LogParamLower(l.LabelName), len(categories))
for _, category := range categories {
labelIds = append(labelIds, category.LabelID)

View File

@@ -3,6 +3,8 @@ package server
import (
"time"
"github.com/photoprism/photoprism/pkg/txt"
"github.com/gin-gonic/gin"
)
@@ -32,7 +34,7 @@ func Logger() gin.HandlerFunc {
// Use debug level to keep production logs clean.
log.Debugf("http: %s %s (%3d) [%v]",
method,
path,
txt.LogParam(path),
statusCode,
latency,
)

View File

@@ -83,7 +83,7 @@ func (s *security) process(w http.ResponseWriter, r *http.Request) error {
if !isGoodHost {
s.opt.BadHostHandler.ServeHTTP(w, r)
return fmt.Errorf("http: bad host %s", txt.Quote(r.Host))
return fmt.Errorf("http: bad host %s", txt.LogParam(r.Host))
}
}

View File

@@ -25,7 +25,7 @@ func MarkUploadAsFavorite(fileName string) {
// Abort if YAML file already exists to avoid overwriting metadata.
if fs.FileExists(yamlName) {
log.Warnf("webdav: %s already exists", txt.Quote(filepath.Base(yamlName)))
log.Warnf("webdav: %s already exists", txt.LogParam(filepath.Base(yamlName)))
return
}
@@ -42,7 +42,7 @@ func MarkUploadAsFavorite(fileName string) {
}
// Log success.
log.Infof("webdav: marked %s as favorite", txt.Quote(filepath.Base(fileName)))
log.Infof("webdav: marked %s as favorite", txt.LogParam(filepath.Base(fileName)))
}
// WebDAV handles any requests to /originals|import/*
@@ -67,11 +67,11 @@ func WebDAV(path string, router *gin.RouterGroup, conf *config.Config) {
if err != nil {
switch r.Method {
case MethodPut, MethodPost, MethodPatch, MethodDelete, MethodCopy, MethodMove:
log.Errorf("webdav: %s in %s %s", txt.Quote(err.Error()), r.Method, r.URL)
log.Errorf("webdav: %s in %s %s", txt.LogParam(err.Error()), txt.LogParam(r.Method), txt.LogParam(r.URL.String()))
case MethodPropfind:
log.Tracef("webdav: %s in %s %s", txt.Quote(err.Error()), r.Method, r.URL)
log.Tracef("webdav: %s in %s %s", txt.LogParam(err.Error()), txt.LogParam(r.Method), txt.LogParam(r.URL.String()))
default:
log.Debugf("webdav: %s in %s %s", txt.Quote(err.Error()), r.Method, r.URL)
log.Debugf("webdav: %s in %s %s", txt.LogParam(err.Error()), txt.LogParam(r.Method), txt.LogParam(r.URL.String()))
}
} else {
@@ -86,7 +86,7 @@ func WebDAV(path string, router *gin.RouterGroup, conf *config.Config) {
switch r.Method {
case MethodPut, MethodPost, MethodPatch, MethodDelete, MethodCopy, MethodMove:
log.Infof("webdav: %s %s", r.Method, r.URL)
log.Infof("webdav: %s %s", txt.LogParam(r.Method), txt.LogParam(r.URL.String()))
if router.BasePath() == WebDAVOriginals {
auto.ShouldIndex()
@@ -94,7 +94,7 @@ func WebDAV(path string, router *gin.RouterGroup, conf *config.Config) {
auto.ShouldImport()
}
default:
log.Tracef("webdav: %s %s", r.Method, r.URL)
log.Tracef("webdav: %s %s", txt.LogParam(r.Method), txt.LogParam(r.URL.String()))
}
}
},

View File

@@ -35,7 +35,7 @@ func FileName(hash string, thumbPath string, width, height int, opts ...Resample
}
if len(hash) < 4 {
return "", fmt.Errorf("resample: file hash is empty or too short (%s)", txt.Quote(hash))
return "", fmt.Errorf("resample: file hash is empty or too short (%s)", txt.LogParam(hash))
}
if len(thumbPath) == 0 {
@@ -57,11 +57,11 @@ func FileName(hash string, thumbPath string, width, height int, opts ...Resample
// FromCache returns the thumb cache file name for an image.
func FromCache(imageFilename, hash, thumbPath string, width, height int, opts ...ResampleOption) (fileName string, err error) {
if len(hash) < 4 {
return "", fmt.Errorf("resample: invalid file hash %s", txt.Quote(hash))
return "", fmt.Errorf("resample: invalid file hash %s", txt.LogParam(hash))
}
if len(imageFilename) < 4 {
return "", fmt.Errorf("resample: invalid file name %s", txt.Quote(imageFilename))
return "", fmt.Errorf("resample: invalid file name %s", txt.LogParam(imageFilename))
}
fileName, err = FileName(hash, thumbPath, width, height, opts...)
@@ -135,7 +135,7 @@ func Create(img image.Image, fileName string, width, height int, opts ...Resampl
err = imaging.Save(result, fileName, saveOption)
if err != nil {
log.Errorf("resample: failed to save %s", txt.Quote(filepath.Base(fileName)))
log.Errorf("resample: failed to save %s", txt.LogParam(filepath.Base(fileName)))
return result, err
}

View File

@@ -272,7 +272,7 @@ func TestFromFile(t *testing.T) {
t.Fatal("error expected")
}
assert.Equal(t, "", fileName)
assert.Equal(t, "resample: invalid file name “”", err.Error())
assert.Equal(t, "resample: invalid file name ''", err.Error())
})
}
@@ -325,7 +325,7 @@ func TestFromCache(t *testing.T) {
if err == nil {
t.Fatal("error expected")
}
assert.Equal(t, "resample: invalid file name “”", err.Error())
assert.Equal(t, "resample: invalid file name ''", err.Error())
assert.Empty(t, fileName)
})
}

View File

@@ -12,7 +12,7 @@ func Jpeg(srcFilename, jpgFilename string, orientation int) (img image.Image, er
img, err = imaging.Open(srcFilename)
if err != nil {
log.Errorf("resample: can't open %s", txt.Quote(filepath.Base(srcFilename)))
log.Errorf("resample: can't open %s", txt.LogParam(filepath.Base(srcFilename)))
return img, err
}
@@ -23,7 +23,7 @@ func Jpeg(srcFilename, jpgFilename string, orientation int) (img image.Image, er
saveOption := imaging.JPEGQuality(JpegQuality)
if err = imaging.Save(img, jpgFilename, saveOption); err != nil {
log.Errorf("resample: failed to save %s", txt.Quote(filepath.Base(jpgFilename)))
log.Errorf("resample: failed to save %s", txt.LogParam(filepath.Base(jpgFilename)))
return img, err
}

View File

@@ -49,7 +49,7 @@ func OpenJpeg(fileName string, orientation int) (result image.Image, err error)
return result, fmt.Errorf("filename missing")
}
logName := txt.Quote(filepath.Base(fileName))
logName := txt.LogParam(filepath.Base(fileName))
// Open file.
fileReader, err := os.Open(fileName)
@@ -81,7 +81,7 @@ func OpenJpeg(fileName string, orientation int) (result image.Image, err error)
// Do nothing.
log.Tracef("resample: detected no color profile in %s", logName)
} else if profile, err := iccProfile.Description(); err == nil && profile != "" {
log.Debugf("resample: detected color profile %s in %s", txt.Quote(profile), logName)
log.Debugf("resample: detected color profile %s in %s", txt.LogParam(profile), logName)
switch {
case colors.ProfileDisplayP3.Equal(profile):
img = colors.ToSRGB(img, colors.ProfileDisplayP3)

View File

@@ -56,7 +56,7 @@ func (worker *Sync) upload(a entity.Account) (complete bool, err error) {
continue // try again next time
}
log.Infof("sync: uploaded %s to %s (%s)", txt.Quote(file.FileName), txt.Quote(remoteName), a.AccName)
log.Infof("sync: uploaded %s to %s (%s)", txt.LogParam(file.FileName), txt.LogParam(remoteName), a.AccName)
fileSync := entity.NewFileSync(a.ID, remoteName)
fileSync.Status = entity.FileSyncUploaded

45
pkg/txt/log.go Normal file
View File

@@ -0,0 +1,45 @@
package txt
import (
"fmt"
"strings"
"unicode"
)
// LogParam sanitizes strings created from user input in response to the log4j debacle.
func LogParam(s string) string {
if len(s) > ClipTitle || strings.Contains(s, "ldap:/") {
return "?"
}
// Trim quotes, tabs, and newline characters.
s = strings.Trim(s, "'\"“`\t\n\r")
// Remove non-printable and other potentially problematic characters.
s = strings.Map(func(r rune) rune {
if !unicode.IsPrint(r) {
return -1
}
switch r {
case '`', '"':
return '\''
case '~', '\\', '|', '$', '<', '>', '{', '}', '∅':
return '?'
default:
return r
}
}, s)
// Empty?
if s == "" || strings.ContainsAny(s, " ") {
return fmt.Sprintf("'%s'", s)
}
return s
}
// LogParamLower sanitizes strings created from user input and converts them to lowercase.
func LogParamLower(s string) string {
return LogParam(strings.ToLower(s))
}

Some files were not shown because too many files have changed in this diff Show More