Stacks: Add advanced indexing options #681 #667 #593

This commit is contained in:
Michael Mayer
2020-12-07 16:19:03 +01:00
parent 335b7ff246
commit ae0af699c6
19 changed files with 369 additions and 170 deletions

Binary file not shown.

View File

@@ -78,7 +78,7 @@ msgstr "Aktionen"
msgid "Add Album" msgid "Add Album"
msgstr "Neues Album erstellen" msgstr "Neues Album erstellen"
#: src/pages/settings/general.vue:269 #: src/pages/settings/general.vue:377
msgid "Add files to your library via Web Upload." msgid "Add files to your library via Web Upload."
msgstr "Dateien über den Browser hochladen und indizieren." msgstr "Dateien über den Browser hochladen und indizieren."
@@ -230,7 +230,7 @@ msgstr "Höhe (m)"
msgid "An error occurred - are you offline?" msgid "An error occurred - are you offline?"
msgstr "Server nicht erreichbar - offline?" msgstr "Server nicht erreichbar - offline?"
#: src/pages/settings/general.vue:590 #: src/pages/settings/general.vue:698
msgid "Animation" msgid "Animation"
msgstr "Animation" msgstr "Animation"
@@ -254,7 +254,7 @@ msgid "Approve"
msgstr "Übernehmen" msgstr "Übernehmen"
#: src/component/navigation.vue:114 src/component/photo/cards.vue:20 #: src/component/navigation.vue:114 src/component/photo/cards.vue:20
#: src/component/photo/clipboard.vue:211 src/pages/settings/general.vue:334 #: src/component/photo/clipboard.vue:211 src/pages/settings/general.vue:442
#: src/routes.js:185 #: src/routes.js:185
msgid "Archive" msgid "Archive"
msgstr "Archiv" msgstr "Archiv"
@@ -295,13 +295,13 @@ msgstr "Seitenverhältnis"
msgid "At least 6 characters." msgid "At least 6 characters."
msgstr "Mindestens 6 Zeichen." msgstr "Mindestens 6 Zeichen."
#: src/pages/settings/general.vue:121 #: src/pages/settings/general.vue:123
msgid "" msgid ""
"Automatically create JPEGs for other file types so that they can be " "Automatically create JPEGs for other file types so that they can be "
"displayed in a browser." "displayed in a browser."
msgstr "" msgstr ""
"RAW-Bilder und Videos müssen zu JPEGs konvertiert werden, damit sie in der " "Videos und andere Bild-Formate nach JPEG konvertieren, damit sie indexiert "
"Suche angezeigt werden können." "und angezeigt werden können."
#: src/pages/settings.vue:8 #: src/pages/settings.vue:8
msgid "Backup" msgid "Backup"
@@ -319,11 +319,11 @@ msgstr "Blau"
msgid "Brown" msgid "Brown"
msgstr "Braun" msgstr "Braun"
#: src/pages/settings/general.vue:423 #: src/pages/settings/general.vue:531
msgid "Browse and edit image classification labels." msgid "Browse and edit image classification labels."
msgstr "Automatische Bild-Kategorisierung sehen und bearbeiten." msgstr "Automatische Bild-Kategorisierung sehen und bearbeiten."
#: src/pages/settings/general.vue:379 #: src/pages/settings/general.vue:487
msgid "Browse indexed files and folders in Library." msgid "Browse indexed files and folders in Library."
msgstr "Durchsuche indizierte Dateien und Verzeichnisse." msgstr "Durchsuche indizierte Dateien und Verzeichnisse."
@@ -384,7 +384,7 @@ msgstr "Kategorie"
msgid "Change" msgid "Change"
msgstr "Ändern" msgstr "Ändern"
#: src/pages/settings/general.vue:357 #: src/pages/settings/general.vue:465
msgid "Change photo titles, locations and other metadata." msgid "Change photo titles, locations and other metadata."
msgstr "Titel, Datum, Ort und andere Metadaten können geändert werden." msgstr "Titel, Datum, Ort und andere Metadaten können geändert werden."
@@ -453,7 +453,7 @@ msgstr "Enthält einen Eintrag."
msgid "Contributors" msgid "Contributors"
msgstr "Contributors" msgstr "Contributors"
#: src/pages/settings/general.vue:120 #: src/pages/settings/general.vue:122
msgid "Convert to JPEG" msgid "Convert to JPEG"
msgstr "Automatisch konvertieren" msgstr "Automatisch konvertieren"
@@ -587,7 +587,7 @@ msgstr "Fertig."
#: src/component/album/clipboard.vue:111 src/component/album/toolbar.vue:106 #: src/component/album/clipboard.vue:111 src/component/album/toolbar.vue:106
#: src/component/file/clipboard.vue:64 src/component/photo/clipboard.vue:165 #: src/component/file/clipboard.vue:64 src/component/photo/clipboard.vue:165
#: src/component/photo/viewer.vue:72 src/dialog/photo/files.vue:33 #: src/component/photo/viewer.vue:72 src/dialog/photo/files.vue:33
#: src/pages/settings/general.vue:290 src/share/album/clipboard.vue:60 #: src/pages/settings/general.vue:398 src/share/album/clipboard.vue:60
#: src/share/photo/clipboard.vue:62 src/share/photos.vue:75 #: src/share/photo/clipboard.vue:62 src/share/photos.vue:75
msgid "Download" msgid "Download"
msgstr "Download" msgstr "Download"
@@ -596,7 +596,7 @@ msgstr "Download"
msgid "Download remote files" msgid "Download remote files"
msgstr "Dateien herunterladen" msgstr "Dateien herunterladen"
#: src/pages/settings/general.vue:291 #: src/pages/settings/general.vue:399
msgid "Download single files and zip archives." msgid "Download single files and zip archives."
msgstr "" msgstr ""
"Einzelne Fotos, Videos sowie Zip-Archive können heruntergeladen werden." "Einzelne Fotos, Videos sowie Zip-Archive können heruntergeladen werden."
@@ -623,7 +623,7 @@ msgstr "E-Mail"
#: src/component/album/clipboard.vue:89 src/component/album/toolbar.vue:69 #: src/component/album/clipboard.vue:89 src/component/album/toolbar.vue:69
#: src/component/photo/clipboard.vue:119 src/component/photo/viewer.vue:89 #: src/component/photo/clipboard.vue:119 src/component/photo/viewer.vue:89
#: src/pages/settings/general.vue:356 #: src/pages/settings/general.vue:464
msgid "Edit" msgid "Edit"
msgstr "Bearbeiten" msgstr "Bearbeiten"
@@ -663,7 +663,7 @@ msgstr "Fehler"
msgid "Every two days" msgid "Every two days"
msgstr "Jeden zweiten Tag" msgstr "Jeden zweiten Tag"
#: src/pages/settings/general.vue:77 #: src/pages/settings/general.vue:79
msgid "" msgid ""
"Exclude content marked as private from search results, shared albums, labels " "Exclude content marked as private from search results, shared albums, labels "
"and places." "and places."
@@ -731,17 +731,21 @@ msgstr "Datei"
msgid "File Browser" msgid "File Browser"
msgstr "Datei Browser" msgstr "Datei Browser"
#: src/pages/settings/general.vue:248
msgid "File Name Prefix"
msgstr "Fortlaufender Name"
#: src/dialog/photo/edit.vue:31 #: src/dialog/photo/edit.vue:31
msgid "Files" msgid "Files"
msgstr "Dateien" msgstr "Dateien"
#: src/pages/settings/general.vue:143 #: src/pages/settings/general.vue:249
msgid "" msgid ""
"Files with sequential names like 'IMG_1234 (2)' or 'IMG_1234 copy 2' belong " "Files with sequential names like 'IMG_1234 (2)' and 'IMG_1234 (3)' belong to "
"to the same photo." "the same picture."
msgstr "" msgstr ""
"Dateien mit Namen wie IMG_1234 (2) oder IMG_1234 copy 2 werden als " "Dateien mit fortlaufenden Namen wie IMG_1234 (2) und IMG_1234 (3) "
"Stapel zusammengefasst." "gehören zum gleichen Bild."
#: src/dialog/photo/details.vue:476 #: src/dialog/photo/details.vue:476
msgid "Focal Length" msgid "Focal Length"
@@ -814,11 +818,11 @@ msgstr "Unsichtbar"
msgid "Hidden Files" msgid "Hidden Files"
msgstr "Unsichtbare Dateien" msgstr "Unsichtbare Dateien"
#: src/pages/settings/general.vue:335 #: src/pages/settings/general.vue:443
msgid "Hide photos that have been moved to archive." msgid "Hide photos that have been moved to archive."
msgstr "Archivierte Inhalte werden nicht in den Suchergebnissen angezeigt." msgstr "Archivierte Inhalte werden nicht in den Suchergebnissen angezeigt."
#: src/pages/settings/general.vue:76 #: src/pages/settings/general.vue:78
msgid "Hide Private" msgid "Hide Private"
msgstr "Privates ausblenden" msgstr "Privates ausblenden"
@@ -852,7 +856,7 @@ msgstr "Bild"
msgid "Image" msgid "Image"
msgstr "Bild" msgstr "Bild"
#: src/pages/library/import.vue:43 src/pages/settings/general.vue:466 #: src/pages/library/import.vue:43 src/pages/settings/general.vue:574
msgid "Import" msgid "Import"
msgstr "Import" msgstr "Import"
@@ -868,7 +872,7 @@ msgstr ""
"Import kopiert neue Dateien und sortiert sie nach Datum, um Duplikate zu " "Import kopiert neue Dateien und sortiert sie nach Datum, um Duplikate zu "
"vermeiden." "vermeiden."
#: src/pages/settings/general.vue:467 #: src/pages/settings/general.vue:575
msgid "Imported files will be sorted by date and given a unique name." msgid "Imported files will be sorted by date and given a unique name."
msgstr "" msgstr ""
"Import kopiert neue Dateien und sortiert sie nach Datum, um Duplikate zu " "Import kopiert neue Dateien und sortiert sie nach Datum, um Duplikate zu "
@@ -935,7 +939,7 @@ msgid "Label Name"
msgstr "Name" msgstr "Name"
#: src/component/navigation.vue:263 src/dialog/photo/edit.vue:27 #: src/component/navigation.vue:263 src/dialog/photo/edit.vue:27
#: src/pages/settings/general.vue:422 src/routes.js:236 #: src/pages/settings/general.vue:530 src/routes.js:236
msgid "Labels" msgid "Labels"
msgstr "Kategorien" msgstr "Kategorien"
@@ -943,7 +947,7 @@ msgstr "Kategorien"
msgid "Labels deleted" msgid "Labels deleted"
msgstr "Kategorien gelöscht" msgstr "Kategorien gelöscht"
#: src/pages/settings/general.vue:220 #: src/pages/settings/general.vue:328
msgid "Language" msgid "Language"
msgstr "Sprache" msgstr "Sprache"
@@ -963,14 +967,14 @@ msgstr "Lavendel"
msgid "Lens" msgid "Lens"
msgstr "Objektiv" msgstr "Objektiv"
#: src/pages/settings/general.vue:401 #: src/pages/settings/general.vue:509
msgid "Let PhotoPrism create albums from past events." msgid "Let PhotoPrism create albums from past events."
msgstr "" msgstr ""
"PhotoPrism erstellt automatisch Alben mit besonderen Momenten, Reisen und " "PhotoPrism erstellt automatisch Alben mit besonderen Momenten, Reisen und "
"Orten." "Orten."
#: src/component/navigation.vue:276 src/component/navigation.vue:285 #: src/component/navigation.vue:276 src/component/navigation.vue:285
#: src/pages/settings/general.vue:6 src/pages/settings/general.vue:444 #: src/pages/settings/general.vue:6 src/pages/settings/general.vue:552
#: src/routes.js:255 src/routes.js:262 src/routes.js:269 #: src/routes.js:255 src/routes.js:262 src/routes.js:269
msgid "Library" msgid "Library"
msgstr "Dateien" msgstr "Dateien"
@@ -1033,7 +1037,7 @@ msgstr "Anmelden"
msgid "Logout" msgid "Logout"
msgstr "Abmelden" msgstr "Abmelden"
#: src/pages/library.vue:17 src/pages/settings/general.vue:488 #: src/pages/library.vue:17 src/pages/settings/general.vue:596
msgid "Logs" msgid "Logs"
msgstr "Logs" msgstr "Logs"
@@ -1069,7 +1073,7 @@ msgstr "Nachricht versendet"
msgid "Missing" msgid "Missing"
msgstr "Fehlend" msgstr "Fehlend"
#: src/component/navigation.vue:218 src/pages/settings/general.vue:400 #: src/component/navigation.vue:218 src/pages/settings/general.vue:508
#: src/routes.js:98 src/routes.js:105 #: src/routes.js:98 src/routes.js:105
msgid "Moments" msgid "Moments"
msgstr "Erlebnisse" msgstr "Erlebnisse"
@@ -1196,7 +1200,7 @@ msgstr ""
#: src/component/photo/list.vue:15 src/component/photo/list.vue:1 #: src/component/photo/list.vue:15 src/component/photo/list.vue:1
#: src/component/photo/list.vue:19 src/component/photo/mosaic.vue:15 #: src/component/photo/list.vue:19 src/component/photo/mosaic.vue:15
#: src/component/photo/mosaic.vue:1 src/dialog/upload.vue:50 #: src/component/photo/mosaic.vue:1 src/dialog/upload.vue:50
#: src/pages/settings/general.vue:99 #: src/pages/settings/general.vue:101
msgid "" msgid ""
"Non-photographic and low-quality images require a review before they appear " "Non-photographic and low-quality images require a review before they appear "
"in search results." "in search results."
@@ -1305,7 +1309,7 @@ msgid "Original Name"
msgstr "Originalname" msgstr "Originalname"
#: src/component/navigation.vue:293 src/pages/library/files.vue:6 #: src/component/navigation.vue:293 src/pages/library/files.vue:6
#: src/pages/settings/general.vue:378 #: src/pages/settings/general.vue:486
msgid "Originals" msgid "Originals"
msgstr "Originale" msgstr "Originale"
@@ -1374,8 +1378,12 @@ msgstr "Pink"
msgid "Place" msgid "Place"
msgstr "Ort" msgstr "Ort"
#: src/pages/settings/general.vue:204
msgid "Place & Time"
msgstr "Gleicher Ort & Zeit"
#: src/component/navigation.vue:231 src/component/navigation.vue:240 #: src/component/navigation.vue:231 src/component/navigation.vue:240
#: src/pages/settings/general.vue:124 src/pages/settings/general.vue:510 #: src/pages/settings/general.vue:152 src/pages/settings/general.vue:618
#: src/routes.js:192 src/routes.js:198 src/routes.js:204 src/routes.js:211 #: src/routes.js:192 src/routes.js:198 src/routes.js:204 src/routes.js:211
msgid "Places" msgid "Places"
msgstr "Karten" msgstr "Karten"
@@ -1442,7 +1450,7 @@ msgstr "Projektion"
msgid "Purple" msgid "Purple"
msgstr "Purpur" msgstr "Purpur"
#: src/pages/settings/general.vue:98 #: src/pages/settings/general.vue:100
msgid "Quality Filter" msgid "Quality Filter"
msgstr "Qualitätsfilter" msgstr "Qualitätsfilter"
@@ -1562,7 +1570,7 @@ msgstr "Scans"
msgid "Search" msgid "Search"
msgstr "Suche" msgstr "Suche"
#: src/pages/settings/general.vue:511 #: src/pages/settings/general.vue:619
msgid "Search and display photos on a map." msgid "Search and display photos on a map."
msgstr "Fotos und Videos auf verschiedenen Weltkarten anzeigen und filtern." msgstr "Fotos und Videos auf verschiedenen Weltkarten anzeigen und filtern."
@@ -1629,7 +1637,7 @@ msgid "Setup"
msgstr "Einrichtung" msgstr "Einrichtung"
#: src/component/album/clipboard.vue:68 src/component/album/toolbar.vue:87 #: src/component/album/clipboard.vue:68 src/component/album/toolbar.vue:87
#: src/component/photo/clipboard.vue:73 src/pages/settings/general.vue:312 #: src/component/photo/clipboard.vue:73 src/pages/settings/general.vue:420
msgid "Share" msgid "Share"
msgstr "Teilen" msgstr "Teilen"
@@ -1645,7 +1653,7 @@ msgstr "Mit dir geteilt."
msgid "Show less" msgid "Show less"
msgstr "Weniger zeigen" msgstr "Weniger zeigen"
#: src/pages/settings/general.vue:445 #: src/pages/settings/general.vue:553
msgid "Show Library in navigation menu." msgid "Show Library in navigation menu."
msgstr "Datei-Verwaltung in der Navigation anzeigen." msgstr "Datei-Verwaltung in der Navigation anzeigen."
@@ -1653,7 +1661,7 @@ msgstr "Datei-Verwaltung in der Navigation anzeigen."
msgid "Show more" msgid "Show more"
msgstr "Mehr zeigen" msgstr "Mehr zeigen"
#: src/pages/settings/general.vue:489 #: src/pages/settings/general.vue:597
msgid "Show server logs in Library." msgid "Show server logs in Library."
msgstr "Server-Ereignisprotokoll anzeigen, um Fehler zu finden." msgstr "Server-Ereignisprotokoll anzeigen, um Fehler zu finden."
@@ -1699,14 +1707,32 @@ msgstr "Quelle"
msgid "Spanish" msgid "Spanish"
msgstr "Spanisch" msgstr "Spanisch"
#: src/pages/settings/general.vue:142 #: src/pages/settings/general.vue:227
msgid "Stack Sequences" msgid "Stack files sharing the same unique image or instance identifier."
msgstr "Sequenzen gruppieren" msgstr "Bilder mit identischer ID als Stapel indexieren und anzeigen."
#: src/component/navigation.vue:89 #: src/pages/settings/general.vue:38
msgid "Stack files with matching..."
msgstr "Als Stapel zusammenfassen..."
#: src/pages/settings/general.vue:205
msgid ""
"Stack pictures taken at the exact same time and location based on their "
"metadata."
msgstr "Aufnahmen mit übereinstimmenden Metadaten gruppieren."
#: src/component/navigation.vue:89 src/pages/settings/general.vue:144
msgid "Stacks" msgid "Stacks"
msgstr "Bildstapel" msgstr "Bildstapel"
#: src/pages/settings/general.vue:145
msgid ""
"Stacks group files with a similar frame of reference, but differences of "
"quality, format, size or color."
msgstr ""
"Bildstapel enthalten zusammengehörige Aufnahmen, die jedoch Unterschiede in "
"Qualität, Format, Größe oder Farben aufweisen können."
#: src/pages/library/index.vue:30 #: src/pages/library/index.vue:30
msgid "Start" msgid "Start"
msgstr "Start" msgstr "Start"
@@ -1731,7 +1757,7 @@ msgstr "Ablageverzeichnis"
msgid "Streets" msgid "Streets"
msgstr "Straßen" msgstr "Straßen"
#: src/pages/settings/general.vue:568 #: src/pages/settings/general.vue:676
msgid "Style" msgid "Style"
msgstr "Style" msgstr "Style"
@@ -1777,7 +1803,7 @@ msgstr ""
"Ihr Format wird möglicherweise nicht unterstützt, es handelt sich um " "Ihr Format wird möglicherweise nicht unterstützt, es handelt sich um "
"Duplikate oder sie wurden noch nicht nach JPEG konvertiert." "Duplikate oder sie wurden noch nicht nach JPEG konvertiert."
#: src/pages/settings/general.vue:198 #: src/pages/settings/general.vue:306
msgid "Theme" msgid "Theme"
msgstr "Theme" msgstr "Theme"
@@ -1844,6 +1870,10 @@ msgstr "Versuche es mit anderen Filtern oder Suchbegriffen."
msgid "Type" msgid "Type"
msgstr "Typ" msgstr "Typ"
#: src/pages/settings/general.vue:226
msgid "Unique ID"
msgstr "Eindeutige Bild-ID"
#: src/dialog/photo/details.vue:16 src/dialog/photo/info.vue:21 #: src/dialog/photo/details.vue:16 src/dialog/photo/info.vue:21
#: src/model/album.js:122 src/model/photo.js:401 src/model/photo.js:415 #: src/model/album.js:122 src/model/photo.js:401 src/model/photo.js:415
#: src/model/photo.js:438 src/model/photo.js:452 src/model/photo.js:529 #: src/model/photo.js:438 src/model/photo.js:452 src/model/photo.js:529
@@ -1869,7 +1899,7 @@ msgstr "Geändert"
#: src/component/album/toolbar.vue:175 src/component/navigation.vue:130 #: src/component/album/toolbar.vue:175 src/component/navigation.vue:130
#: src/component/photo/toolbar.vue:123 src/dialog/share/upload.vue:35 #: src/component/photo/toolbar.vue:123 src/dialog/share/upload.vue:35
#: src/dialog/upload.vue:8 src/dialog/upload.vue:54 src/pages/albums.vue:134 #: src/dialog/upload.vue:8 src/dialog/upload.vue:54 src/pages/albums.vue:134
#: src/pages/library/import.vue:38 src/pages/settings/general.vue:268 #: src/pages/library/import.vue:38 src/pages/settings/general.vue:376
#: src/pages/settings/sync.vue:24 #: src/pages/settings/sync.vue:24
msgid "Upload" msgid "Upload"
msgstr "Upload" msgstr "Upload"
@@ -1890,7 +1920,7 @@ msgstr "Upload fehlgeschlagen"
msgid "Upload local files" msgid "Upload local files"
msgstr "Dateien hochladen" msgstr "Dateien hochladen"
#: src/pages/settings/general.vue:313 #: src/pages/settings/general.vue:421
msgid "Upload to WebDAV and share links with friends." msgid "Upload to WebDAV and share links with friends."
msgstr "Teile Fotos, Videos und Alben mit Freunden." msgstr "Teile Fotos, Videos und Alben mit Freunden."
@@ -1914,7 +1944,7 @@ msgstr "URL"
msgid "User" msgid "User"
msgstr "Benutzer" msgstr "Benutzer"
#: src/pages/settings/general.vue:38 #: src/pages/settings/general.vue:66
msgid "User Interface" msgid "User Interface"
msgstr "Benutzeroberfläche" msgstr "Benutzeroberfläche"
@@ -2003,6 +2033,9 @@ msgstr "Ihre Nachricht wurde gesendet"
msgid "Zoom in/out" msgid "Zoom in/out"
msgstr "Zoom in/out" msgstr "Zoom in/out"
#~ msgid "Stack Sequences"
#~ msgstr "Sequenzen gruppieren"
#~ msgid "Brazilian Portuguese" #~ msgid "Brazilian Portuguese"
#~ msgstr "Brasilianisches Portugiesisch" #~ msgstr "Brasilianisches Portugiesisch"

File diff suppressed because one or more lines are too long

View File

@@ -78,7 +78,7 @@ msgstr ""
msgid "Add Album" msgid "Add Album"
msgstr "" msgstr ""
#: src/pages/settings/general.vue:269 #: src/pages/settings/general.vue:377
msgid "Add files to your library via Web Upload." msgid "Add files to your library via Web Upload."
msgstr "" msgstr ""
@@ -234,7 +234,7 @@ msgstr ""
msgid "An error occurred - are you offline?" msgid "An error occurred - are you offline?"
msgstr "" msgstr ""
#: src/pages/settings/general.vue:590 #: src/pages/settings/general.vue:698
msgid "Animation" msgid "Animation"
msgstr "" msgstr ""
@@ -259,7 +259,7 @@ msgstr ""
#: src/component/navigation.vue:114 #: src/component/navigation.vue:114
#: src/component/photo/cards.vue:20 #: src/component/photo/cards.vue:20
#: src/component/photo/clipboard.vue:211 #: src/component/photo/clipboard.vue:211
#: src/pages/settings/general.vue:334 #: src/pages/settings/general.vue:442
#: src/routes.js:185 #: src/routes.js:185
msgid "Archive" msgid "Archive"
msgstr "" msgstr ""
@@ -300,7 +300,7 @@ msgstr ""
msgid "At least 6 characters." msgid "At least 6 characters."
msgstr "" msgstr ""
#: src/pages/settings/general.vue:121 #: src/pages/settings/general.vue:123
msgid "Automatically create JPEGs for other file types so that they can be displayed in a browser." msgid "Automatically create JPEGs for other file types so that they can be displayed in a browser."
msgstr "" msgstr ""
@@ -320,11 +320,11 @@ msgstr ""
msgid "Brown" msgid "Brown"
msgstr "" msgstr ""
#: src/pages/settings/general.vue:423 #: src/pages/settings/general.vue:531
msgid "Browse and edit image classification labels." msgid "Browse and edit image classification labels."
msgstr "" msgstr ""
#: src/pages/settings/general.vue:379 #: src/pages/settings/general.vue:487
msgid "Browse indexed files and folders in Library." msgid "Browse indexed files and folders in Library."
msgstr "" msgstr ""
@@ -404,7 +404,7 @@ msgstr ""
msgid "Change" msgid "Change"
msgstr "" msgstr ""
#: src/pages/settings/general.vue:357 #: src/pages/settings/general.vue:465
msgid "Change photo titles, locations and other metadata." msgid "Change photo titles, locations and other metadata."
msgstr "" msgstr ""
@@ -476,7 +476,7 @@ msgstr ""
msgid "Contributors" msgid "Contributors"
msgstr "" msgstr ""
#: src/pages/settings/general.vue:120 #: src/pages/settings/general.vue:122
msgid "Convert to JPEG" msgid "Convert to JPEG"
msgstr "" msgstr ""
@@ -636,7 +636,7 @@ msgstr ""
#: src/component/photo/clipboard.vue:165 #: src/component/photo/clipboard.vue:165
#: src/component/photo/viewer.vue:72 #: src/component/photo/viewer.vue:72
#: src/dialog/photo/files.vue:33 #: src/dialog/photo/files.vue:33
#: src/pages/settings/general.vue:290 #: src/pages/settings/general.vue:398
#: src/share/album/clipboard.vue:60 #: src/share/album/clipboard.vue:60
#: src/share/photo/clipboard.vue:62 #: src/share/photo/clipboard.vue:62
#: src/share/photos.vue:75 #: src/share/photos.vue:75
@@ -647,7 +647,7 @@ msgstr ""
msgid "Download remote files" msgid "Download remote files"
msgstr "" msgstr ""
#: src/pages/settings/general.vue:291 #: src/pages/settings/general.vue:399
msgid "Download single files and zip archives." msgid "Download single files and zip archives."
msgstr "" msgstr ""
@@ -679,7 +679,7 @@ msgstr ""
#: src/component/album/toolbar.vue:69 #: src/component/album/toolbar.vue:69
#: src/component/photo/clipboard.vue:119 #: src/component/photo/clipboard.vue:119
#: src/component/photo/viewer.vue:89 #: src/component/photo/viewer.vue:89
#: src/pages/settings/general.vue:356 #: src/pages/settings/general.vue:464
msgid "Edit" msgid "Edit"
msgstr "" msgstr ""
@@ -720,7 +720,7 @@ msgstr ""
msgid "Every two days" msgid "Every two days"
msgstr "" msgstr ""
#: src/pages/settings/general.vue:77 #: src/pages/settings/general.vue:79
msgid "Exclude content marked as private from search results, shared albums, labels and places." msgid "Exclude content marked as private from search results, shared albums, labels and places."
msgstr "" msgstr ""
@@ -788,12 +788,16 @@ msgstr ""
msgid "File Browser" msgid "File Browser"
msgstr "" msgstr ""
#: src/pages/settings/general.vue:248
msgid "File Name Prefix"
msgstr ""
#: src/dialog/photo/edit.vue:31 #: src/dialog/photo/edit.vue:31
msgid "Files" msgid "Files"
msgstr "" msgstr ""
#: src/pages/settings/general.vue:143 #: src/pages/settings/general.vue:249
msgid "Files with sequential names like 'IMG_1234 (2)' or 'IMG_1234 copy 2' belong to the same photo." msgid "Files with sequential names like 'IMG_1234 (2)' and 'IMG_1234 (3)' belong to the same picture."
msgstr "" msgstr ""
#: src/dialog/photo/details.vue:476 #: src/dialog/photo/details.vue:476
@@ -873,11 +877,11 @@ msgstr ""
msgid "Hidden Files" msgid "Hidden Files"
msgstr "" msgstr ""
#: src/pages/settings/general.vue:335 #: src/pages/settings/general.vue:443
msgid "Hide photos that have been moved to archive." msgid "Hide photos that have been moved to archive."
msgstr "" msgstr ""
#: src/pages/settings/general.vue:76 #: src/pages/settings/general.vue:78
msgid "Hide Private" msgid "Hide Private"
msgstr "" msgstr ""
@@ -909,7 +913,7 @@ msgid "Image"
msgstr "" msgstr ""
#: src/pages/library/import.vue:43 #: src/pages/library/import.vue:43
#: src/pages/settings/general.vue:466 #: src/pages/settings/general.vue:574
msgid "Import" msgid "Import"
msgstr "" msgstr ""
@@ -921,7 +925,7 @@ msgstr ""
msgid "Imported files will be sorted by date and given a unique name to avoid duplicates." msgid "Imported files will be sorted by date and given a unique name to avoid duplicates."
msgstr "" msgstr ""
#: src/pages/settings/general.vue:467 #: src/pages/settings/general.vue:575
msgid "Imported files will be sorted by date and given a unique name." msgid "Imported files will be sorted by date and given a unique name."
msgstr "" msgstr ""
@@ -990,7 +994,7 @@ msgstr ""
#: src/component/navigation.vue:263 #: src/component/navigation.vue:263
#: src/dialog/photo/edit.vue:27 #: src/dialog/photo/edit.vue:27
#: src/pages/settings/general.vue:422 #: src/pages/settings/general.vue:530
#: src/routes.js:236 #: src/routes.js:236
msgid "Labels" msgid "Labels"
msgstr "" msgstr ""
@@ -999,7 +1003,7 @@ msgstr ""
msgid "Labels deleted" msgid "Labels deleted"
msgstr "" msgstr ""
#: src/pages/settings/general.vue:220 #: src/pages/settings/general.vue:328
msgid "Language" msgid "Language"
msgstr "" msgstr ""
@@ -1020,14 +1024,14 @@ msgstr ""
msgid "Lens" msgid "Lens"
msgstr "" msgstr ""
#: src/pages/settings/general.vue:401 #: src/pages/settings/general.vue:509
msgid "Let PhotoPrism create albums from past events." msgid "Let PhotoPrism create albums from past events."
msgstr "" msgstr ""
#: src/component/navigation.vue:276 #: src/component/navigation.vue:276
#: src/component/navigation.vue:285 #: src/component/navigation.vue:285
#: src/pages/settings/general.vue:6 #: src/pages/settings/general.vue:6
#: src/pages/settings/general.vue:444 #: src/pages/settings/general.vue:552
#: src/routes.js:255 #: src/routes.js:255
#: src/routes.js:262 #: src/routes.js:262
#: src/routes.js:269 #: src/routes.js:269
@@ -1093,7 +1097,7 @@ msgid "Logout"
msgstr "" msgstr ""
#: src/pages/library.vue:17 #: src/pages/library.vue:17
#: src/pages/settings/general.vue:488 #: src/pages/settings/general.vue:596
msgid "Logs" msgid "Logs"
msgstr "" msgstr ""
@@ -1131,7 +1135,7 @@ msgid "Missing"
msgstr "" msgstr ""
#: src/component/navigation.vue:218 #: src/component/navigation.vue:218
#: src/pages/settings/general.vue:400 #: src/pages/settings/general.vue:508
#: src/routes.js:98 #: src/routes.js:98
#: src/routes.js:105 #: src/routes.js:105
msgid "Moments" msgid "Moments"
@@ -1280,7 +1284,7 @@ msgstr ""
#: src/component/photo/mosaic.vue:15 #: src/component/photo/mosaic.vue:15
#: src/component/photo/mosaic.vue:1 #: src/component/photo/mosaic.vue:1
#: src/dialog/upload.vue:50 #: src/dialog/upload.vue:50
#: src/pages/settings/general.vue:99 #: src/pages/settings/general.vue:101
msgid "Non-photographic and low-quality images require a review before they appear in search results." msgid "Non-photographic and low-quality images require a review before they appear in search results."
msgstr "" msgstr ""
@@ -1380,7 +1384,7 @@ msgstr ""
#: src/component/navigation.vue:293 #: src/component/navigation.vue:293
#: src/pages/library/files.vue:6 #: src/pages/library/files.vue:6
#: src/pages/settings/general.vue:378 #: src/pages/settings/general.vue:486
msgid "Originals" msgid "Originals"
msgstr "" msgstr ""
@@ -1448,10 +1452,14 @@ msgstr ""
msgid "Place" msgid "Place"
msgstr "" msgstr ""
#: src/pages/settings/general.vue:204
msgid "Place & Time"
msgstr ""
#: src/component/navigation.vue:231 #: src/component/navigation.vue:231
#: src/component/navigation.vue:240 #: src/component/navigation.vue:240
#: src/pages/settings/general.vue:124 #: src/pages/settings/general.vue:152
#: src/pages/settings/general.vue:510 #: src/pages/settings/general.vue:618
#: src/routes.js:192 #: src/routes.js:192
#: src/routes.js:198 #: src/routes.js:198
#: src/routes.js:204 #: src/routes.js:204
@@ -1524,7 +1532,7 @@ msgstr ""
msgid "Purple" msgid "Purple"
msgstr "" msgstr ""
#: src/pages/settings/general.vue:98 #: src/pages/settings/general.vue:100
msgid "Quality Filter" msgid "Quality Filter"
msgstr "" msgstr ""
@@ -1653,7 +1661,7 @@ msgstr ""
msgid "Search" msgid "Search"
msgstr "" msgstr ""
#: src/pages/settings/general.vue:511 #: src/pages/settings/general.vue:619
msgid "Search and display photos on a map." msgid "Search and display photos on a map."
msgstr "" msgstr ""
@@ -1732,7 +1740,7 @@ msgstr ""
#: src/component/album/clipboard.vue:68 #: src/component/album/clipboard.vue:68
#: src/component/album/toolbar.vue:87 #: src/component/album/toolbar.vue:87
#: src/component/photo/clipboard.vue:73 #: src/component/photo/clipboard.vue:73
#: src/pages/settings/general.vue:312 #: src/pages/settings/general.vue:420
msgid "Share" msgid "Share"
msgstr "" msgstr ""
@@ -1748,7 +1756,7 @@ msgstr ""
msgid "Show less" msgid "Show less"
msgstr "" msgstr ""
#: src/pages/settings/general.vue:445 #: src/pages/settings/general.vue:553
msgid "Show Library in navigation menu." msgid "Show Library in navigation menu."
msgstr "" msgstr ""
@@ -1756,7 +1764,7 @@ msgstr ""
msgid "Show more" msgid "Show more"
msgstr "" msgstr ""
#: src/pages/settings/general.vue:489 #: src/pages/settings/general.vue:597
msgid "Show server logs in Library." msgid "Show server logs in Library."
msgstr "" msgstr ""
@@ -1805,14 +1813,27 @@ msgstr ""
msgid "Spanish" msgid "Spanish"
msgstr "" msgstr ""
#: src/pages/settings/general.vue:142 #: src/pages/settings/general.vue:227
msgid "Stack Sequences" msgid "Stack files sharing the same unique image or instance identifier."
msgstr ""
#: src/pages/settings/general.vue:38
msgid "Stack files with matching..."
msgstr ""
#: src/pages/settings/general.vue:205
msgid "Stack pictures taken at the exact same time and location based on their metadata."
msgstr "" msgstr ""
#: src/component/navigation.vue:89 #: src/component/navigation.vue:89
#: src/pages/settings/general.vue:144
msgid "Stacks" msgid "Stacks"
msgstr "" msgstr ""
#: src/pages/settings/general.vue:145
msgid "Stacks group files with a similar frame of reference, but differences of quality, format, size or color."
msgstr ""
#: src/pages/library/index.vue:30 #: src/pages/library/index.vue:30
msgid "Start" msgid "Start"
msgstr "" msgstr ""
@@ -1837,7 +1858,7 @@ msgstr ""
msgid "Streets" msgid "Streets"
msgstr "" msgstr ""
#: src/pages/settings/general.vue:568 #: src/pages/settings/general.vue:676
msgid "Style" msgid "Style"
msgstr "" msgstr ""
@@ -1879,7 +1900,7 @@ msgstr ""
msgid "Their format may not be supported, they haven't been converted to JPEG yet or there are duplicates." msgid "Their format may not be supported, they haven't been converted to JPEG yet or there are duplicates."
msgstr "" msgstr ""
#: src/pages/settings/general.vue:198 #: src/pages/settings/general.vue:306
msgid "Theme" msgid "Theme"
msgstr "" msgstr ""
@@ -1956,6 +1977,10 @@ msgstr ""
msgid "Type" msgid "Type"
msgstr "" msgstr ""
#: src/pages/settings/general.vue:226
msgid "Unique ID"
msgstr ""
#: src/dialog/photo/details.vue:16 #: src/dialog/photo/details.vue:16
#: src/dialog/photo/info.vue:21 #: src/dialog/photo/info.vue:21
#: src/model/album.js:122 #: src/model/album.js:122
@@ -1998,7 +2023,7 @@ msgstr ""
#: src/dialog/upload.vue:54 #: src/dialog/upload.vue:54
#: src/pages/albums.vue:134 #: src/pages/albums.vue:134
#: src/pages/library/import.vue:38 #: src/pages/library/import.vue:38
#: src/pages/settings/general.vue:268 #: src/pages/settings/general.vue:376
#: src/pages/settings/sync.vue:24 #: src/pages/settings/sync.vue:24
msgid "Upload" msgid "Upload"
msgstr "" msgstr ""
@@ -2019,7 +2044,7 @@ msgstr ""
msgid "Upload local files" msgid "Upload local files"
msgstr "" msgstr ""
#: src/pages/settings/general.vue:313 #: src/pages/settings/general.vue:421
msgid "Upload to WebDAV and share links with friends." msgid "Upload to WebDAV and share links with friends."
msgstr "" msgstr ""
@@ -2045,7 +2070,7 @@ msgstr ""
msgid "User" msgid "User"
msgstr "" msgstr ""
#: src/pages/settings/general.vue:38 #: src/pages/settings/general.vue:66
msgid "User Interface" msgid "User Interface"
msgstr "" msgstr ""

View File

@@ -61,12 +61,70 @@
<v-checkbox <v-checkbox
@change="onChange" @change="onChange"
:disabled="busy" :disabled="busy"
class="ma-0 pa-0 input-sequences" class="ma-0 pa-0 input-stacks"
v-model="settings.index.sequences" v-model="settings.index.stacks"
color="secondary-dark" color="secondary-dark"
:label="$gettext('Stack Sequences')" :label="$gettext('Stacks')"
:hint="$gettext('Files with sequential names like \'IMG_1234 (2)\' or \'IMG_1234 copy 2\' belong to the same photo.')" :hint="$gettext('Stacks group files with a similar frame of reference, but differences of quality, format, size or color.')"
prepend-icon="photo_library" prepend-icon="burst_mode"
persistent-hint
>
</v-checkbox>
</v-flex>
</v-layout>
</v-card-actions>
</v-card>
<v-card flat tile class="mt-0 px-1 application" v-show="settings.index.stacks">
<v-card-title primary-title class="pb-0">
<h3 class="body-2 mb-0">
<translate>Stack files with matching...</translate>
</h3>
</v-card-title>
<v-card-actions>
<v-layout wrap align-top>
<v-flex xs12 sm6 lg4 class="px-2 pb-2 pt-2">
<v-checkbox
@change="onChange"
:disabled="busy"
class="ma-0 pa-0 input-stack-meta"
v-model="settings.stack.meta"
color="secondary-dark"
:label="$gettext('Place & Time')"
:hint="$gettext('Stack pictures taken at the exact same time and location based on their metadata.')"
prepend-icon="schedule"
persistent-hint
>
</v-checkbox>
</v-flex>
<v-flex xs12 sm6 lg4 class="px-2 pb-2 pt-2">
<v-checkbox
@change="onChange"
:disabled="busy"
class="ma-0 pa-0 input-stack-uuid"
v-model="settings.stack.uuid"
color="secondary-dark"
:label="$gettext('Unique ID')"
:hint="$gettext('Stack files sharing the same unique image or instance identifier.')"
prepend-icon="fingerprint"
persistent-hint
>
</v-checkbox>
</v-flex>
<v-flex xs12 sm6 lg4 class="px-2 pb-2 pt-2">
<v-checkbox
@change="onChange"
:disabled="busy"
class="ma-0 pa-0 input-stack-sequences"
v-model="settings.stack.sequences"
color="secondary-dark"
:label="$gettext('File Name Prefix')"
:hint="$gettext('Files with sequential names like \'IMG_1234 (2)\' and \'IMG_1234 (3)\' belong to the same picture.')"
prepend-icon="spellcheck"
persistent-hint persistent-hint
> >
</v-checkbox> </v-checkbox>

View File

@@ -49,7 +49,7 @@ func StartIndexing(router *gin.RouterGroup) {
indOpt := photoprism.IndexOptions{ indOpt := photoprism.IndexOptions{
Rescan: f.Rescan, Rescan: f.Rescan,
Convert: conf.Settings().Index.Convert && conf.SidecarWritable(), Convert: conf.Settings().Index.Convert && conf.SidecarWritable(),
Stack: conf.Settings().Index.Stack, Stack: conf.Settings().Index.Stacks,
Path: filepath.Clean(f.Path), Path: filepath.Clean(f.Path),
} }

View File

@@ -63,7 +63,7 @@ func indexAction(ctx *cli.Context) error {
Path: subPath, Path: subPath,
Rescan: ctx.Bool("all"), Rescan: ctx.Bool("all"),
Convert: conf.Settings().Index.Convert && conf.SidecarWritable(), Convert: conf.Settings().Index.Convert && conf.SidecarWritable(),
Stack: conf.Settings().Index.Stack, Stack: conf.Settings().Index.Stacks,
} }
indexed := ind.Start(indOpt) indexed := ind.Start(indOpt)

View File

@@ -27,21 +27,6 @@ type MapsSettings struct {
Style string `json:"style" yaml:"style"` Style string `json:"style" yaml:"style"`
} }
// IndexSettings represents indexing settings.
type IndexSettings struct {
Path string `json:"path" yaml:"path"`
Convert bool `json:"convert" yaml:"convert"`
Rescan bool `json:"rescan" yaml:"rescan"`
Sequences bool `json:"sequences" yaml:"sequences"`
Stack bool `json:"stack" yaml:"stack"`
}
// ImportSettings represents import settings.
type ImportSettings struct {
Path string `json:"path" yaml:"path"`
Move bool `json:"move" yaml:"move"`
}
// FeatureSettings represents feature flags, mainly for the Web UI. // FeatureSettings represents feature flags, mainly for the Web UI.
type FeatureSettings struct { type FeatureSettings struct {
Upload bool `json:"upload" yaml:"upload"` Upload bool `json:"upload" yaml:"upload"`
@@ -60,6 +45,27 @@ type FeatureSettings struct {
Logs bool `json:"logs" yaml:"logs"` Logs bool `json:"logs" yaml:"logs"`
} }
// ImportSettings represents import settings.
type ImportSettings struct {
Path string `json:"path" yaml:"path"`
Move bool `json:"move" yaml:"move"`
}
// IndexSettings represents indexing settings.
type IndexSettings struct {
Path string `json:"path" yaml:"path"`
Convert bool `json:"convert" yaml:"convert"`
Rescan bool `json:"rescan" yaml:"rescan"`
Stacks bool `json:"stacks" yaml:"stacks"`
}
// StackSettings represents file stack settings.
type StackSettings struct {
UUID bool `json:"uuid" yaml:"uuid"`
Meta bool `json:"meta" yaml:"meta"`
Sequences bool `json:"sequences" yaml:"sequences"`
}
// Settings represents user settings for Web UI, indexing, and import. // Settings represents user settings for Web UI, indexing, and import.
type Settings struct { type Settings struct {
Theme string `json:"theme" yaml:"theme"` Theme string `json:"theme" yaml:"theme"`
@@ -69,6 +75,7 @@ type Settings struct {
Features FeatureSettings `json:"features" yaml:"features"` Features FeatureSettings `json:"features" yaml:"features"`
Import ImportSettings `json:"import" yaml:"import"` Import ImportSettings `json:"import" yaml:"import"`
Index IndexSettings `json:"index" yaml:"index"` Index IndexSettings `json:"index" yaml:"index"`
Stack StackSettings `json:"stack" yaml:"stack"`
} }
// NewSettings creates a new Settings instance. // NewSettings creates a new Settings instance.
@@ -107,8 +114,12 @@ func NewSettings() *Settings {
Path: "/", Path: "/",
Rescan: false, Rescan: false,
Convert: true, Convert: true,
Sequences: true, Stacks: true,
Stack: true, },
Stack: StackSettings{
UUID: true,
Meta: true,
Sequences: false,
}, },
} }
} }

View File

@@ -27,5 +27,8 @@ index:
path: / path: /
convert: true convert: true
rescan: false rescan: false
sequences: true stacks: true
stack: true stack:
uuid: true
meta: true
sequences: false

View File

@@ -1012,13 +1012,27 @@ func (m *Photo) MapKey() string {
} }
// Stack merges the photo with identical ones. // Stack merges the photo with identical ones.
func (m *Photo) Stack() (identical Photos, err error) { func (m *Photo) Stack(meta, uuid bool) (identical Photos, err error) {
if err := Db(). if !meta && !uuid {
return identical, nil
}
stmt := Db().
Where("id <> ?", m.ID). Where("id <> ?", m.ID).
Where("photo_single = 0"). Where("photo_single = 0")
Where("(taken_at = ? AND cell_id = ? AND camera_serial = ? AND camera_id = ?) OR (uuid <> '' AND uuid = ?)",
m.TakenAt, m.CellID, m.CameraSerial, m.CameraID, m.UUID). switch {
Find(&identical).Error; err != nil { case meta && uuid:
stmt.Where("(taken_at = ? AND taken_src = 'meta' AND cell_id = ? AND camera_serial = ? AND camera_id = ?) OR (uuid <> '' AND uuid = ?)",
m.TakenAt, m.CellID, m.CameraSerial, m.CameraID, m.UUID)
case meta:
stmt.Where("taken_at = ? AND taken_src = 'meta' AND cell_id = ? AND camera_serial = ? AND camera_id = ?",
m.TakenAt, m.CellID, m.CameraSerial, m.CameraID)
case uuid:
stmt.Where("uuid <> '' AND uuid = ?", m.UUID)
}
if err := stmt.Find(&identical).Error; err != nil {
return identical, err return identical, err
} }

View File

@@ -115,7 +115,7 @@ func (c *Convert) Start(path string) error {
// ToJson uses exiftool to export metadata to a json file. // ToJson uses exiftool to export metadata to a json file.
func (c *Convert) ToJson(mf *MediaFile) (*MediaFile, error) { func (c *Convert) ToJson(mf *MediaFile) (*MediaFile, error) {
jsonName := fs.TypeJson.FindFirst(mf.FileName(), []string{c.conf.SidecarPath(), fs.HiddenPath}, c.conf.OriginalsPath(), c.conf.Settings().Index.Sequences) jsonName := fs.TypeJson.FindFirst(mf.FileName(), []string{c.conf.SidecarPath(), fs.HiddenPath}, c.conf.OriginalsPath(), c.conf.Settings().Stack.Sequences)
result, err := NewMediaFile(jsonName) result, err := NewMediaFile(jsonName)
@@ -127,7 +127,7 @@ func (c *Convert) ToJson(mf *MediaFile) (*MediaFile, error) {
return nil, fmt.Errorf("convert: can't create json sidecar file for %s in read only mode", txt.Quote(mf.BaseName())) return nil, fmt.Errorf("convert: can't create json sidecar file for %s in read only mode", txt.Quote(mf.BaseName()))
} }
jsonName = fs.FileName(mf.FileName(), c.conf.SidecarPath(), c.conf.OriginalsPath(), ".json", c.conf.Settings().Index.Sequences) jsonName = fs.FileName(mf.FileName(), c.conf.SidecarPath(), c.conf.OriginalsPath(), ".json", c.conf.Settings().Stack.Sequences)
fileName := mf.RelName(c.conf.OriginalsPath()) fileName := mf.RelName(c.conf.OriginalsPath())
@@ -220,7 +220,7 @@ func (c *Convert) ToJpeg(image *MediaFile) (*MediaFile, error) {
return image, nil return image, nil
} }
jpegName := fs.TypeJpeg.FindFirst(image.FileName(), []string{c.conf.SidecarPath(), fs.HiddenPath}, c.conf.OriginalsPath(), c.conf.Settings().Index.Sequences) jpegName := fs.TypeJpeg.FindFirst(image.FileName(), []string{c.conf.SidecarPath(), fs.HiddenPath}, c.conf.OriginalsPath(), c.conf.Settings().Stack.Sequences)
mediaFile, err := NewMediaFile(jpegName) mediaFile, err := NewMediaFile(jpegName)
@@ -232,12 +232,12 @@ func (c *Convert) ToJpeg(image *MediaFile) (*MediaFile, error) {
return nil, fmt.Errorf("convert: disabled in read only mode (%s)", image.RelName(c.conf.OriginalsPath())) return nil, fmt.Errorf("convert: disabled in read only mode (%s)", image.RelName(c.conf.OriginalsPath()))
} }
jpegName = fs.FileName(image.FileName(), c.conf.SidecarPath(), c.conf.OriginalsPath(), fs.JpegExt, c.conf.Settings().Index.Sequences) jpegName = fs.FileName(image.FileName(), c.conf.SidecarPath(), c.conf.OriginalsPath(), fs.JpegExt, c.conf.Settings().Stack.Sequences)
fileName := image.RelName(c.conf.OriginalsPath()) fileName := image.RelName(c.conf.OriginalsPath())
log.Debugf("convert: %s -> %s", fileName, filepath.Base(jpegName)) log.Debugf("convert: %s -> %s", fileName, filepath.Base(jpegName))
xmpName := fs.TypeXMP.Find(image.FileName(), c.conf.Settings().Index.Sequences) xmpName := fs.TypeXMP.Find(image.FileName(), c.conf.Settings().Stack.Sequences)
event.Publish("index.converting", event.Data{ event.Publish("index.converting", event.Data{
"fileType": image.FileType(), "fileType": image.FileType(),
@@ -308,7 +308,7 @@ func (c *Convert) ToAvc1(video *MediaFile) (*MediaFile, error) {
return video, nil return video, nil
} }
avcName := fs.TypeMp4.FindFirst(video.FileName(), []string{c.conf.SidecarPath(), fs.HiddenPath}, c.conf.OriginalsPath(), c.conf.Settings().Index.Sequences) avcName := fs.TypeMp4.FindFirst(video.FileName(), []string{c.conf.SidecarPath(), fs.HiddenPath}, c.conf.OriginalsPath(), c.conf.Settings().Stack.Sequences)
mediaFile, err := NewMediaFile(avcName) mediaFile, err := NewMediaFile(avcName)
@@ -320,7 +320,7 @@ func (c *Convert) ToAvc1(video *MediaFile) (*MediaFile, error) {
return nil, fmt.Errorf("convert: disabled in read only mode (%s)", video.RelName(c.conf.OriginalsPath())) return nil, fmt.Errorf("convert: disabled in read only mode (%s)", video.RelName(c.conf.OriginalsPath()))
} }
avcName = fs.FileName(video.FileName(), c.conf.SidecarPath(), c.conf.OriginalsPath(), fs.AvcExt, c.conf.Settings().Index.Sequences) avcName = fs.FileName(video.FileName(), c.conf.SidecarPath(), c.conf.OriginalsPath(), fs.AvcExt, c.conf.Settings().Stack.Sequences)
fileName := video.RelName(c.conf.OriginalsPath()) fileName := video.RelName(c.conf.OriginalsPath())
log.Debugf("convert: %s -> %s", fileName, filepath.Base(avcName)) log.Debugf("convert: %s -> %s", fileName, filepath.Base(avcName))

View File

@@ -151,7 +151,7 @@ func (imp *Import) Start(opt ImportOptions) fs.Done {
return nil return nil
} }
related, err := mf.RelatedFiles(imp.conf.Settings().Index.Sequences) related, err := mf.RelatedFiles(imp.conf.Settings().Stack.Sequences)
if err != nil { if err != nil {
event.Error(fmt.Sprintf("import: %s", err.Error())) event.Error(fmt.Sprintf("import: %s", err.Error()))

View File

@@ -113,7 +113,7 @@ func ImportWorker(jobs <-chan ImportJob) {
} }
} }
related, err := f.RelatedFiles(imp.conf.Settings().Index.Sequences) related, err := f.RelatedFiles(imp.conf.Settings().Stack.Sequences)
if err != nil { if err != nil {
log.Errorf("import: %s in %s (find related files)", err.Error(), txt.Quote(fs.RelName(destinationMainFilename, imp.originalsPath()))) log.Errorf("import: %s in %s (find related files)", err.Error(), txt.Quote(fs.RelName(destinationMainFilename, imp.originalsPath())))

View File

@@ -167,7 +167,7 @@ func (ind *Index) Start(opt IndexOptions) fs.Done {
return nil return nil
} }
related, err := mf.RelatedFiles(ind.conf.Settings().Index.Sequences) related, err := mf.RelatedFiles(ind.conf.Settings().Stack.Sequences)
if err != nil { if err != nil {
log.Warnf("index: %s", err.Error()) log.Warnf("index: %s", err.Error())
@@ -222,7 +222,7 @@ func (ind *Index) Start(opt IndexOptions) fs.Done {
} }
if opt.Stack { if opt.Stack {
if err := ind.StackIdenticalPhotos(); err != nil { if err := ind.StackPhotos(); err != nil {
log.Errorf("index: %s", err) log.Errorf("index: %s", err)
} }
} }
@@ -240,16 +240,16 @@ func (ind *Index) Start(opt IndexOptions) fs.Done {
return done return done
} }
// StackIdenticalPhotos stacks files that belong to the same photo. // StackPhotos stacks files that belong to the same photo.
func (ind *Index) StackIdenticalPhotos() error { func (ind *Index) StackPhotos() error {
photos, err := query.IdenticalPhotos() photos, err := query.MatchingPhotos(ind.conf.Settings().Stack.Meta, ind.conf.Settings().Stack.UUID)
if err != nil { if err != nil {
return err return err
} }
for _, photo := range photos { for _, photo := range photos {
if merged, err := photo.Stack(); err != nil { if merged, err := photo.Stack(ind.conf.Settings().Stack.Meta, ind.conf.Settings().Stack.UUID); err != nil {
log.Errorf("index: %s", err) log.Errorf("index: %s", err)
} else { } else {
log.Infof("index: merged photo uid %s with %s", photo.PhotoUID, merged.UIDs()) log.Infof("index: merged photo uid %s with %s", photo.PhotoUID, merged.UIDs())

View File

@@ -114,7 +114,7 @@ func (ind *Index) MediaFile(m *MediaFile, o IndexOptions, originalName string) (
photoExists := false photoExists := false
stripSequence := Config().Settings().Index.Sequences stripSequence := Config().Settings().Stack.Sequences
event.Publish("index.indexing", event.Data{ event.Publish("index.indexing", event.Data{
"fileHash": fileHash, "fileHash": fileHash,
@@ -156,23 +156,24 @@ func (ind *Index) MediaFile(m *MediaFile, o IndexOptions, originalName string) (
} }
} }
// Try to find existing photo by file path and name. // Look for existing photo if file wasn't indexed yet...
if !fileExists { if !fileExists {
photoQuery = entity.UnscopedDb().First(&photo, "photo_path = ? AND photo_name = ?", filePath, fileBase) photoQuery = entity.UnscopedDb().First(&photo, "photo_path = ? AND photo_name = ?", filePath, fileBase)
// Add file to existing photo (file stack)? // Stack file based on matching location and time metadata?
if o.Stack { if o.Stack && Config().Settings().Stack.Meta {
// Try to find existing photo by exact time and location.
if photoQuery.Error != nil && m.MetaData().HasTimeAndPlace() { if photoQuery.Error != nil && m.MetaData().HasTimeAndPlace() {
metaData = m.MetaData() metaData = m.MetaData()
photoQuery = entity.UnscopedDb().First(&photo, "photo_lat = ? AND photo_lng = ? AND taken_at = ? AND camera_serial = ?", metaData.Lat, metaData.Lng, metaData.TakenAt, metaData.CameraSerial) photoQuery = entity.UnscopedDb().First(&photo, "photo_lat = ? AND photo_lng = ? AND taken_at = ? AND taken_src = 'meta' AND camera_serial = ?", metaData.Lat, metaData.Lng, metaData.TakenAt, metaData.CameraSerial)
if photoQuery.Error == nil { if photoQuery.Error == nil {
fileStacked = true fileStacked = true
} }
} }
}
// Try to find existing photo by unique image id. // Stack file based on the same unique ID?
if o.Stack && Config().Settings().Stack.UUID {
if photoQuery.Error != nil && m.MetaData().HasDocumentID() { if photoQuery.Error != nil && m.MetaData().HasDocumentID() {
photoQuery = entity.UnscopedDb().First(&photo, "uuid = ?", m.MetaData().DocumentID) photoQuery = entity.UnscopedDb().First(&photo, "uuid = ?", m.MetaData().DocumentID)

View File

@@ -379,7 +379,7 @@ func (m *MediaFile) PathNameInfo() (fileRoot, fileBase, relativePath, relativeNa
rootPath = Config().OriginalsPath() rootPath = Config().OriginalsPath()
} }
fileBase = m.BasePrefix(Config().Settings().Index.Sequences) fileBase = m.BasePrefix(Config().Settings().Stack.Sequences)
relativePath = m.RelPath(rootPath) relativePath = m.RelPath(rootPath)
relativeName = m.RelName(rootPath) relativeName = m.RelName(rootPath)

View File

@@ -110,23 +110,46 @@ func PhotosCheck(limit int, offset int) (entities entity.Photos, err error) {
return entities, err return entities, err
} }
// IdenticalPhotos returns photos sharing the same exact time, location and camera serial. // MatchingPhotos returns photos sharing the same exact time and location, or unique image id.
func IdenticalPhotos() (entities entity.Photos, err error) { func MatchingPhotos(meta, uuid bool) (entities entity.Photos, err error) {
err = UnscopedDb().Table("photos"). if !meta && !uuid {
Select("photos.*"). return entities, nil
Joins(`JOIN photos dup ON photos.id < dup.id }
AND photos.photo_single = 0
AND dup.photo_single = 0 stmt := UnscopedDb().Table("photos").
AND photos.deleted_at IS NULL Select("photos.*")
AND dup.deleted_at IS NULL
AND ((photos.photo_lat = dup.photo_lat switch {
case meta && uuid:
stmt.Joins(`JOIN photos dup ON photos.id < dup.id
AND photos.photo_single = 0 AND dup.photo_single = 0
AND photos.deleted_at IS NULL AND dup.deleted_at IS NULL
AND ((photos.taken_src = 'meta' AND dup.taken_src = 'meta'
AND photos.photo_lat = dup.photo_lat
AND photos.photo_lng = dup.photo_lng AND photos.photo_lng = dup.photo_lng
AND photos.taken_at = dup.taken_at AND photos.taken_at = dup.taken_at
AND photos.camera_id = dup.camera_id AND photos.camera_id = dup.camera_id
AND photos.camera_serial = dup.camera_serial) OR AND photos.camera_serial = dup.camera_serial) OR
(photos.uuid <> '' AND photos.uuid = dup.uuid))`). (photos.uuid <> '' AND photos.uuid = dup.uuid))`)
Group("photos.id"). case meta:
Find(&entities).Error stmt.Joins(`JOIN photos dup ON photos.id < dup.id
AND photos.photo_single = 0
AND dup.photo_single = 0
AND photos.deleted_at IS NULL AND dup.deleted_at IS NULL
AND ((photos.taken_src = 'meta' AND dup.taken_src = 'meta'
AND photos.photo_lat = dup.photo_lat
AND photos.photo_lng = dup.photo_lng
AND photos.taken_at = dup.taken_at
AND photos.camera_id = dup.camera_id
AND photos.camera_serial = dup.camera_serial))`)
case uuid:
stmt.Joins(`JOIN photos dup ON photos.id < dup.id
AND photos.photo_single = 0 AND dup.photo_single = 0
AND photos.deleted_at IS NULL AND dup.deleted_at IS NULL
AND (photos.uuid <> '' AND photos.uuid = dup.uuid)`)
}
err = stmt.Group("photos.id").Find(&entities).Error
return entities, err return entities, err
} }

View File

@@ -80,12 +80,43 @@ func TestPhotosCheck(t *testing.T) {
} }
func TestIdenticalPhotos(t *testing.T) { func TestIdenticalPhotos(t *testing.T) {
result, err := IdenticalPhotos() t.Run("all", func(t *testing.T) {
result, err := MatchingPhotos(true, true)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
assert.IsType(t, entity.Photos{}, result) assert.IsType(t, entity.Photos{}, result)
// t.Logf("%+v", result) })
t.Run("meta", func(t *testing.T) {
result, err := MatchingPhotos(true, false)
if err != nil {
t.Fatal(err)
}
assert.IsType(t, entity.Photos{}, result)
})
t.Run("uuid", func(t *testing.T) {
result, err := MatchingPhotos(false, true)
if err != nil {
t.Fatal(err)
}
assert.IsType(t, entity.Photos{}, result)
})
t.Run("none", func(t *testing.T) {
result, err := MatchingPhotos(false, false)
if err != nil {
t.Fatal(err)
}
assert.IsType(t, entity.Photos{}, result)
})
} }

View File

@@ -35,7 +35,7 @@ func (worker *Sync) relatedDownloads(a entity.Account) (result Downloads, err er
// Group results by directory and base name // Group results by directory and base name
for i, file := range files { for i, file := range files {
k := fs.AbsPrefix(file.RemoteName, worker.conf.Settings().Index.Sequences) k := fs.AbsPrefix(file.RemoteName, worker.conf.Settings().Stack.Sequences)
result[k] = append(result[k], file) result[k] = append(result[k], file)
@@ -137,7 +137,7 @@ func (worker *Sync) download(a entity.Account) (complete bool, err error) {
continue continue
} }
related, err := mf.RelatedFiles(worker.conf.Settings().Index.Sequences) related, err := mf.RelatedFiles(worker.conf.Settings().Stack.Sequences)
if err != nil { if err != nil {
worker.logWarn(err) worker.logWarn(err)