Skip to content

Commit ba83fce

Browse files
committed
Albums: Prevent the same albums from being created twice photoprism#4849
Signed-off-by: Michael Mayer <michael@photoprism.app>
1 parent 34f3d9e commit ba83fce

File tree

4 files changed

+47
-32
lines changed

4 files changed

+47
-32
lines changed

internal/entity/album.go

+23-9
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"os"
66
"strconv"
77
"strings"
8+
"sync"
89
"time"
910

1011
"github.com/jinzhu/gorm"
@@ -36,6 +37,8 @@ var (
3637
DefaultOrderMonth = sortby.Oldest
3738
)
3839

40+
var albumMutex = sync.Mutex{}
41+
3942
type Albums []Album
4043

4144
// Album represents a photo album
@@ -116,6 +119,9 @@ func AddPhotoToUserAlbums(photoUid string, albums []string, sortOrder, userUid s
116119
return fmt.Errorf("album: can not add invalid photo uid %s", clean.Log(photoUid))
117120
}
118121

122+
albumMutex.Lock()
123+
defer albumMutex.Unlock()
124+
119125
for _, album := range albums {
120126
var albumUid string
121127

@@ -311,7 +317,7 @@ func FindMonthAlbum(year, month int) *Album {
311317
func FindAlbumBySlug(albumSlug, albumType string) *Album {
312318
m := Album{}
313319

314-
if albumSlug == "" {
320+
if albumSlug == "" || albumSlug == UnknownSlug {
315321
return nil
316322
}
317323

@@ -394,13 +400,23 @@ func FindAlbum(find Album) *Album {
394400

395401
// Search by slug and filter or title.
396402
if find.AlbumType != AlbumManual {
397-
if find.AlbumFilter != "" {
403+
if find.AlbumFilter != "" && find.AlbumSlug != UnknownSlug {
398404
stmt = stmt.Where("album_slug = ? OR album_filter = ?", find.AlbumSlug, find.AlbumFilter)
399-
} else {
405+
} else if find.AlbumFilter != "" {
406+
stmt = stmt.Where("album_filter = ?", find.AlbumFilter)
407+
} else if find.AlbumSlug != UnknownSlug {
400408
stmt = stmt.Where("album_slug = ?", find.AlbumSlug)
409+
} else {
410+
return nil
401411
}
402-
} else {
412+
} else if find.AlbumTitle != "" && find.AlbumSlug != UnknownSlug {
403413
stmt = stmt.Where("album_slug = ? OR album_title LIKE ?", find.AlbumSlug, find.AlbumTitle)
414+
} else if find.AlbumSlug != UnknownSlug {
415+
stmt = stmt.Where("album_slug = ?", find.AlbumSlug)
416+
} else if find.AlbumTitle != "" {
417+
stmt = stmt.Where("album_title LIKE ?", find.AlbumTitle)
418+
} else {
419+
return nil
404420
}
405421

406422
// Filter by creator if the album has not been published yet.
@@ -452,7 +468,7 @@ func (m *Album) String() string {
452468
return "Album<nil>"
453469
}
454470

455-
if m.AlbumSlug != "" {
471+
if m.AlbumSlug != "" && m.AlbumSlug != UnknownSlug {
456472
return clean.Log(m.AlbumSlug)
457473
}
458474

@@ -503,7 +519,7 @@ func (m *Album) SetTitle(title string) *Album {
503519
}
504520

505521
if m.AlbumSlug == "" {
506-
m.AlbumSlug = "-"
522+
m.AlbumSlug = UnknownSlug
507523
}
508524

509525
return m
@@ -608,9 +624,7 @@ func (m *Album) UpdateTitleAndState(title, slug, stateName, countryCode string)
608624
return nil
609625
}
610626

611-
if title != "" {
612-
m.SetTitle(title)
613-
}
627+
m.SetTitle(title)
614628

615629
return m.Updates(Map{"album_title": m.AlbumTitle, "album_slug": m.AlbumSlug, "album_location": m.AlbumLocation, "album_country": m.AlbumCountry, "album_state": m.AlbumState})
616630
}

internal/entity/album_test.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ func TestFindAlbum(t *testing.T) {
388388
assert.Equal(t, "Christmas 2030", result.AlbumTitle)
389389
assert.True(t, result.IsDefault())
390390
})
391-
t.Run("Success", func(t *testing.T) {
391+
t.Run("AlbumFolder", func(t *testing.T) {
392392
album := Album{AlbumSlug: "april-1990", AlbumType: AlbumFolder}
393393
result := FindAlbum(album)
394394

@@ -398,7 +398,7 @@ func TestFindAlbum(t *testing.T) {
398398

399399
assert.Equal(t, "April 1990", result.AlbumTitle)
400400
})
401-
t.Run("Success", func(t *testing.T) {
401+
t.Run("AlbumFilter", func(t *testing.T) {
402402
album := Album{AlbumSlug: "april-1990", AlbumType: AlbumFolder, AlbumFilter: "1990/04"}
403403
result := FindAlbum(album)
404404

@@ -408,7 +408,7 @@ func TestFindAlbum(t *testing.T) {
408408

409409
assert.Equal(t, "April 1990", result.AlbumTitle)
410410
})
411-
t.Run("Success", func(t *testing.T) {
411+
t.Run("AlbumManual", func(t *testing.T) {
412412
album := Album{AlbumSlug: "berlin-2019", AlbumType: AlbumManual}
413413
result := FindAlbum(album)
414414

@@ -418,13 +418,13 @@ func TestFindAlbum(t *testing.T) {
418418

419419
assert.Equal(t, "Berlin 2019", result.AlbumTitle)
420420
})
421-
t.Run("NoResult", func(t *testing.T) {
421+
t.Run("CreatedBy", func(t *testing.T) {
422422
album := Album{AlbumSlug: "berlin-2019", AlbumType: AlbumManual, CreatedBy: "xxx"}
423423
result := FindAlbum(album)
424424

425425
assert.Nil(t, result)
426426
})
427-
t.Run("NoResult", func(t *testing.T) {
427+
t.Run("NotFound", func(t *testing.T) {
428428
album := Album{AlbumSlug: "xxx-xxx", AlbumType: AlbumFolder}
429429
result := FindAlbum(album)
430430

internal/entity/entity_const.go

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const (
1212
UnknownMonth = -1
1313
UnknownDay = -1
1414
UnknownID = "zz"
15+
UnknownSlug = "-"
1516
)
1617

1718
// Media types.

internal/photoprism/import_worker.go

+18-18
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ func ImportWorker(jobs <-chan ImportJob) {
153153
continue
154154
}
155155

156-
// Find related files.
156+
// Find and index related originals.
157157
related, err := f.RelatedFiles(imp.conf.Settings().StackSequences())
158158

159159
// Skip import if the finding related files results in an error.
@@ -167,23 +167,23 @@ func ImportWorker(jobs <-chan ImportJob) {
167167
photoUID := ""
168168

169169
if related.Main != nil {
170-
f := related.Main
170+
main := related.Main
171171

172172
// Enforce file size and resolution limits.
173-
if limitErr, _ := f.ExceedsBytes(o.ByteLimit); limitErr != nil {
173+
if limitErr, _ := main.ExceedsBytes(o.ByteLimit); limitErr != nil {
174174
log.Warnf("import: %s", limitErr)
175175
continue
176-
} else if limitErr, _ = f.ExceedsResolution(o.ResolutionLimit); limitErr != nil {
176+
} else if limitErr, _ = main.ExceedsResolution(o.ResolutionLimit); limitErr != nil {
177177
log.Warnf("import: %s", limitErr)
178178
continue
179179
}
180180

181181
// Index main MediaFile.
182-
res := ind.UserMediaFile(f, o, originalName, "", opt.UID)
182+
res := ind.UserMediaFile(main, o, originalName, "", opt.UID)
183183

184184
// Log result.
185-
log.Infof("import: %s main %s file %s", res, f.FileType(), clean.Log(f.RootRelName()))
186-
done[f.FileName()] = true
185+
log.Infof("import: %s main %s file %s", res, main.FileType(), clean.Log(main.RootRelName()))
186+
done[main.FileName()] = true
187187

188188
if !res.Success() {
189189
// Skip importing related files if the main file was not indexed successfully.
@@ -200,44 +200,44 @@ func ImportWorker(jobs <-chan ImportJob) {
200200
log.Warnf("import: no main media file found for %s, creation of a preview image may have failed", clean.Log(f.RootRelName()))
201201
}
202202

203-
for _, f := range related.Files {
204-
if f == nil {
203+
for _, file := range related.Files {
204+
if file == nil {
205205
continue
206206
}
207207

208-
if done[f.FileName()] {
208+
if done[file.FileName()] {
209209
continue
210210
}
211211

212-
done[f.FileName()] = true
212+
done[file.FileName()] = true
213213

214214
// Show warning if sidecar file exceeds size or resolution limit.
215-
if limitErr, _ := f.ExceedsBytes(o.ByteLimit); limitErr != nil {
215+
if limitErr, _ := file.ExceedsBytes(o.ByteLimit); limitErr != nil {
216216
log.Warnf("import: %s", limitErr)
217-
} else if limitErr, _ = f.ExceedsResolution(o.ResolutionLimit); limitErr != nil {
217+
} else if limitErr, _ = file.ExceedsResolution(o.ResolutionLimit); limitErr != nil {
218218
log.Warnf("import: %s", limitErr)
219219
}
220220

221221
// Extract metadata to a JSON file with Exiftool.
222-
if f.NeedsExifToolJson() {
223-
if jsonName, err := imp.convert.ToJson(f, false); err != nil {
222+
if file.NeedsExifToolJson() {
223+
if jsonName, err := imp.convert.ToJson(file, false); err != nil {
224224
log.Tracef("exiftool: %s", clean.Error(err))
225-
log.Debugf("exiftool: failed parsing %s", clean.Log(f.RootRelName()))
225+
log.Debugf("exiftool: failed parsing %s", clean.Log(file.RootRelName()))
226226
} else {
227227
log.Debugf("import: created %s", filepath.Base(jsonName))
228228
}
229229
}
230230

231231
// Index related media file including its original filename.
232-
res := ind.UserMediaFile(f, o, relatedOriginalNames[f.FileName()], photoUID, opt.UID)
232+
res := ind.UserMediaFile(file, o, relatedOriginalNames[file.FileName()], photoUID, opt.UID)
233233

234234
// Save file error.
235235
if fileUid, fileErr := res.FileError(); fileErr != nil {
236236
query.SetFileError(fileUid, clean.Error(fileErr))
237237
}
238238

239239
// Log result.
240-
log.Infof("import: %s related %s file %s", res, f.FileType(), clean.Log(f.RootRelName()))
240+
log.Infof("import: %s related %s file %s", res, file.FileType(), clean.Log(file.RootRelName()))
241241
}
242242
}
243243
}

0 commit comments

Comments
 (0)