Rename "thumbnails" to "thumbs" and group api functions in one file
Signed-off-by: Michael Mayer <michael@liquidbytes.net>
This commit is contained in:
parent
dac846ba01
commit
4d42222caf
|
@ -33,7 +33,7 @@ import PhotoSwipeUI_Default from "photoswipe/dist/photoswipe-ui-default.js";
|
|||
import Event from "pubsub-js";
|
||||
import stripHtml from "string-strip-html";
|
||||
|
||||
const thumbs = window.__CONFIG__.thumbnails;
|
||||
const thumbs = window.__CONFIG__.thumbs;
|
||||
|
||||
class Viewer {
|
||||
constructor() {
|
||||
|
|
|
@ -278,7 +278,7 @@
|
|||
model: Object,
|
||||
},
|
||||
data() {
|
||||
const thumbs = this.$config.values.thumbnails;
|
||||
const thumbs = this.$config.values.thumbs;
|
||||
|
||||
return {
|
||||
options: options,
|
||||
|
|
|
@ -33,7 +33,7 @@ import Api from "common/api";
|
|||
import {config} from "../session";
|
||||
import {$gettext} from "common/vm";
|
||||
|
||||
const thumbs = window.__CONFIG__.thumbnails;
|
||||
const thumbs = window.__CONFIG__.thumbs;
|
||||
|
||||
export class Thumb extends Model {
|
||||
getDefaults() {
|
||||
|
|
Binary file not shown.
|
@ -58,7 +58,7 @@ msgstr "Auf den Link klicken, um ihn zu kopieren."
|
|||
msgid "Account"
|
||||
msgstr "Zugang"
|
||||
|
||||
#: src/dialog/photo/info.vue:122
|
||||
#: src/dialog/photo/info.vue:128
|
||||
msgid "Accuracy"
|
||||
msgstr "Genauigkeit"
|
||||
|
||||
|
@ -78,7 +78,7 @@ msgstr "Link hinzufügen"
|
|||
msgid "Add photos or videos from search results by selecting them."
|
||||
msgstr "Fotos und Videos können über das Kontextmenü hinzugefügt werden."
|
||||
|
||||
#: src/dialog/account/add.vue:5 src/pages/settings/sync.vue:40
|
||||
#: src/dialog/account/add.vue:5 src/pages/settings/sync.vue:46
|
||||
msgid "Add Server"
|
||||
msgstr "Server hinzufügen"
|
||||
|
||||
|
@ -204,7 +204,7 @@ msgstr ""
|
|||
"Alternativ können Dateien auch direkt auf kompatible WebDAV-Server "
|
||||
"hochgeladen z.B. Nextcloud."
|
||||
|
||||
#: src/dialog/photo/info.vue:114
|
||||
#: src/dialog/photo/info.vue:120
|
||||
msgid "Altitude"
|
||||
msgstr "Höhe"
|
||||
|
||||
|
@ -244,7 +244,7 @@ msgstr "Übernehmen"
|
|||
msgid "Archive"
|
||||
msgstr "Archiv"
|
||||
|
||||
#: src/dialog/photo/info.vue:162
|
||||
#: src/dialog/photo/info.vue:168
|
||||
msgid "Archived"
|
||||
msgstr "Archiviert"
|
||||
|
||||
|
@ -310,7 +310,7 @@ msgstr "Kalender"
|
|||
msgid "Camera"
|
||||
msgstr "Kamera"
|
||||
|
||||
#: src/dialog/photo/info.vue:67
|
||||
#: src/dialog/photo/info.vue:73
|
||||
msgid "Camera Serial"
|
||||
msgstr "Kamera-Seriennummer"
|
||||
|
||||
|
@ -354,7 +354,7 @@ msgstr "Als privat markieren"
|
|||
msgid "Change Status"
|
||||
msgstr "Status ändern"
|
||||
|
||||
#: src/dialog/photo/info.vue:154
|
||||
#: src/dialog/photo/info.vue:160
|
||||
msgid "Checked"
|
||||
msgstr "Geprüft"
|
||||
|
||||
|
@ -387,7 +387,7 @@ msgstr "Wahrscheinlichkeit"
|
|||
msgid "Connect"
|
||||
msgstr "Verbinden"
|
||||
|
||||
#: src/dialog/webdav.vue:4 src/pages/settings/sync.vue:45
|
||||
#: src/dialog/webdav.vue:4 src/pages/settings/sync.vue:42
|
||||
msgid "Connect via WebDAV"
|
||||
msgstr "Mit WebDAV verbinden"
|
||||
|
||||
|
@ -439,7 +439,7 @@ msgstr "Land"
|
|||
msgid "Create album"
|
||||
msgstr "Album erstellen"
|
||||
|
||||
#: src/dialog/photo/info.vue:130
|
||||
#: src/dialog/photo/info.vue:136
|
||||
msgid "Created"
|
||||
msgstr "Hinzugefügt"
|
||||
|
||||
|
@ -501,7 +501,7 @@ msgstr "Auflösung"
|
|||
|
||||
#: src/dialog/account/edit.vue:61 src/dialog/account/edit.vue:120
|
||||
msgid "Disabled"
|
||||
msgstr "Aus"
|
||||
msgstr "Deaktiviert"
|
||||
|
||||
#: src/routes.js:290 src/routes.js:297 src/routes.js:304 src/routes.js:311
|
||||
msgid "Discover"
|
||||
|
@ -568,7 +568,7 @@ msgstr "Account bearbeiten"
|
|||
msgid "Edit Photo"
|
||||
msgstr "Foto bearbeiten"
|
||||
|
||||
#: src/dialog/photo/info.vue:146
|
||||
#: src/dialog/photo/info.vue:152
|
||||
msgid "Edited"
|
||||
msgstr "Bearbeitet"
|
||||
|
||||
|
@ -632,7 +632,7 @@ msgstr "Fehler beim Importieren der hochgeladenen Dateien"
|
|||
msgid "Fast"
|
||||
msgstr "Schnell"
|
||||
|
||||
#: src/dialog/photo/info.vue:74
|
||||
#: src/dialog/photo/info.vue:80
|
||||
msgid "Favorite"
|
||||
msgstr "Favorit"
|
||||
|
||||
|
@ -666,8 +666,8 @@ msgid ""
|
|||
"Files with sequential names like 'IMG_1234 (2)' or 'IMG_1234 copy 2' belong "
|
||||
"to the same photo."
|
||||
msgstr ""
|
||||
"Dateien mit Namen wie ‘IMG_1234 (2)’ oder ‘IMG_1234 copy 2’ werden "
|
||||
"zusammengefasst."
|
||||
"Dateien mit Namen wie ‘IMG_1234 (2)’ oder ‘IMG_1234 copy 2’ werden als "
|
||||
"Stapel zusammengefasst."
|
||||
|
||||
#: src/dialog/photo/details.vue:448
|
||||
msgid "Focal Length"
|
||||
|
@ -856,11 +856,11 @@ msgstr "Kategorien gelöscht"
|
|||
msgid "Language"
|
||||
msgstr "Sprache"
|
||||
|
||||
#: src/pages/settings/sync.vue:111
|
||||
#: src/pages/settings/sync.vue:113
|
||||
msgid "Last Backup"
|
||||
msgstr "Letztes Backup"
|
||||
|
||||
#: src/dialog/photo/details.vue:443 src/dialog/photo/info.vue:98
|
||||
#: src/dialog/photo/details.vue:443 src/dialog/photo/info.vue:104
|
||||
msgid "Latitude"
|
||||
msgstr "Breitengrad"
|
||||
|
||||
|
@ -938,7 +938,7 @@ msgstr "Abmelden"
|
|||
msgid "Logs"
|
||||
msgstr "Logs"
|
||||
|
||||
#: src/dialog/photo/details.vue:444 src/dialog/photo/info.vue:106
|
||||
#: src/dialog/photo/details.vue:444 src/dialog/photo/info.vue:112
|
||||
msgid "Longitude"
|
||||
msgstr "Längengrad"
|
||||
|
||||
|
@ -1032,7 +1032,7 @@ msgstr "Name"
|
|||
msgid "Name too long"
|
||||
msgstr "Name zu lang"
|
||||
|
||||
#: src/pages/settings/sync.vue:122 src/resources/options.js:178
|
||||
#: src/pages/settings/sync.vue:129 src/resources/options.js:178
|
||||
#: src/resources/options.js:188
|
||||
msgid "Never"
|
||||
msgstr "Nie"
|
||||
|
@ -1046,8 +1046,8 @@ msgstr "Neues Passwort"
|
|||
msgid "Newest first"
|
||||
msgstr "Neueste zuerst"
|
||||
|
||||
#: src/dialog/photo/archive.vue:13 src/dialog/photo/info.vue:187
|
||||
#: src/dialog/photo/info.vue:218 src/dialog/photo/info.vue:245
|
||||
#: src/dialog/photo/archive.vue:13 src/dialog/photo/info.vue:160
|
||||
#: src/dialog/photo/info.vue:187 src/dialog/photo/info.vue:214
|
||||
msgid "No"
|
||||
msgstr "Nein"
|
||||
|
||||
|
@ -1113,7 +1113,7 @@ msgstr ""
|
|||
"sollen, ist kein Import notwendig. Die Ordner müssen in diesem Fall manuell "
|
||||
"verwaltet und indiziert werden."
|
||||
|
||||
#: src/pages/settings/sync.vue:32
|
||||
#: src/pages/settings/sync.vue:34
|
||||
msgid "Note:"
|
||||
msgstr "Hinweis:"
|
||||
|
||||
|
@ -1299,7 +1299,7 @@ msgstr "Voransicht"
|
|||
msgid "Primary"
|
||||
msgstr "Hauptdatei"
|
||||
|
||||
#: src/component/navigation.vue:129 src/dialog/photo/info.vue:82
|
||||
#: src/component/navigation.vue:129 src/dialog/photo/info.vue:88
|
||||
#: src/routes.js:171
|
||||
msgid "Private"
|
||||
msgstr "Privat"
|
||||
|
@ -1312,7 +1312,7 @@ msgstr "Purpur"
|
|||
msgid "Quality Filter"
|
||||
msgstr "Qualitätsfilter"
|
||||
|
||||
#: src/dialog/photo/info.vue:53
|
||||
#: src/dialog/photo/info.vue:59
|
||||
msgid "Quality Score"
|
||||
msgstr "Qualität"
|
||||
|
||||
|
@ -1370,7 +1370,7 @@ msgstr ""
|
|||
msgid "Request failed - invalid response"
|
||||
msgstr "Anfrage fehlgeschlagen - ungültige Antwort"
|
||||
|
||||
#: src/dialog/photo/info.vue:61
|
||||
#: src/dialog/photo/info.vue:67
|
||||
msgid "Resolution"
|
||||
msgstr "Auflösung"
|
||||
|
||||
|
@ -1395,7 +1395,7 @@ msgstr "Russisch"
|
|||
msgid "Save"
|
||||
msgstr "Speichern"
|
||||
|
||||
#: src/dialog/photo/info.vue:90
|
||||
#: src/dialog/photo/info.vue:96
|
||||
msgid "Scan"
|
||||
msgstr "Scan"
|
||||
|
||||
|
@ -1440,7 +1440,7 @@ msgstr "Auswahl archiviert"
|
|||
msgid "Selection restored"
|
||||
msgstr "Auswahl wiederhergestellt"
|
||||
|
||||
#: src/pages/settings/sync.vue:108
|
||||
#: src/pages/settings/sync.vue:109
|
||||
msgid "Server"
|
||||
msgstr "Server"
|
||||
|
||||
|
@ -1561,7 +1561,7 @@ msgid ""
|
|||
"Support for additional services, like Google Drive, will be added over time."
|
||||
msgstr "Die Unterstützung weiterer Dienste, wie Google Drive, ist geplant."
|
||||
|
||||
#: src/pages/settings/sync.vue:110
|
||||
#: src/pages/settings/sync.vue:111
|
||||
msgid "Sync"
|
||||
msgstr "Sync"
|
||||
|
||||
|
@ -1569,7 +1569,8 @@ msgstr "Sync"
|
|||
msgid "Sync raw images"
|
||||
msgstr "RAW-Dateien sichern"
|
||||
|
||||
#: src/component/photo/list.vue:114 src/share/photo/list.vue:93
|
||||
#: src/component/photo/list.vue:114 src/dialog/photo/info.vue:53
|
||||
#: src/share/photo/list.vue:93
|
||||
msgid "Taken"
|
||||
msgstr "Aufgenommen"
|
||||
|
||||
|
@ -1605,7 +1606,7 @@ msgstr ""
|
|||
msgid "Theme"
|
||||
msgstr "Theme"
|
||||
|
||||
#: src/dialog/webdav.vue:17 src/pages/settings/sync.vue:34
|
||||
#: src/dialog/webdav.vue:17 src/pages/settings/sync.vue:36
|
||||
msgid ""
|
||||
"This mounts the originals folder as a network drive and allows you to open, "
|
||||
"edit, and delete files from your computer or smartphone as if they were "
|
||||
|
@ -1669,7 +1670,7 @@ msgstr "Typ"
|
|||
msgid "UID"
|
||||
msgstr "UID"
|
||||
|
||||
#: src/dialog/photo/details.vue:423 src/dialog/photo/info.vue:221
|
||||
#: src/dialog/photo/details.vue:423 src/dialog/photo/info.vue:227
|
||||
#: src/model/album.js:122 src/model/photo.js:399 src/model/photo.js:413
|
||||
#: src/model/photo.js:436 src/model/photo.js:448 src/model/photo.js:525
|
||||
#: src/model/photo.js:538 src/pages/library/errors.vue:196
|
||||
|
@ -1688,13 +1689,13 @@ msgstr "Unsortiert"
|
|||
msgid "Unstack"
|
||||
msgstr "Aus Stapel entfernen"
|
||||
|
||||
#: src/dialog/photo/files.vue:120 src/dialog/photo/info.vue:138
|
||||
#: src/dialog/photo/files.vue:120 src/dialog/photo/info.vue:144
|
||||
msgid "Updated"
|
||||
msgstr "Geändert"
|
||||
|
||||
#: src/dialog/share/upload.vue:35 src/dialog/upload.vue:8
|
||||
#: src/dialog/upload.vue:54 src/pages/library/import.vue:38
|
||||
#: src/pages/settings/general.vue:319 src/pages/settings/sync.vue:109
|
||||
#: src/pages/settings/general.vue:319 src/pages/settings/sync.vue:110
|
||||
msgid "Upload"
|
||||
msgstr "Upload"
|
||||
|
||||
|
@ -1766,7 +1767,7 @@ msgid "WebDAV clients can connect to PhotoPrism using the following URL:"
|
|||
msgstr ""
|
||||
"WebDAV-Clients können sich über die folgende URL mit PhotoPrism verbinden:"
|
||||
|
||||
#: src/pages/settings/sync.vue:33
|
||||
#: src/pages/settings/sync.vue:35
|
||||
msgid ""
|
||||
"WebDAV clients, like Microsoft’s Windows Explorer or Apple's Finder, can "
|
||||
"connect directly to PhotoPrism."
|
||||
|
@ -1801,8 +1802,8 @@ msgstr "Gelb"
|
|||
|
||||
#: src/dialog/photo/archive.vue:15 src/dialog/photo/files.vue:80
|
||||
#: src/dialog/photo/files.vue:86 src/dialog/photo/files.vue:104
|
||||
#: src/dialog/photo/files.vue:110 src/dialog/photo/info.vue:186
|
||||
#: src/dialog/photo/info.vue:217 src/dialog/photo/info.vue:244
|
||||
#: src/dialog/photo/files.vue:110 src/dialog/photo/info.vue:159
|
||||
#: src/dialog/photo/info.vue:186 src/dialog/photo/info.vue:213
|
||||
msgid "Yes"
|
||||
msgstr "Ja"
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -53,7 +53,7 @@ msgstr ""
|
|||
msgid "Account"
|
||||
msgstr ""
|
||||
|
||||
#: src/dialog/photo/info.vue:122
|
||||
#: src/dialog/photo/info.vue:128
|
||||
msgid "Accuracy"
|
||||
msgstr ""
|
||||
|
||||
|
@ -74,7 +74,7 @@ msgid "Add photos or videos from search results by selecting them."
|
|||
msgstr ""
|
||||
|
||||
#: src/dialog/account/add.vue:5
|
||||
#: src/pages/settings/sync.vue:40
|
||||
#: src/pages/settings/sync.vue:46
|
||||
msgid "Add Server"
|
||||
msgstr ""
|
||||
|
||||
|
@ -206,7 +206,7 @@ msgstr ""
|
|||
msgid "Alternatively, you can upload files directly to WebDAV servers like Nextcloud."
|
||||
msgstr ""
|
||||
|
||||
#: src/dialog/photo/info.vue:114
|
||||
#: src/dialog/photo/info.vue:120
|
||||
msgid "Altitude"
|
||||
msgstr ""
|
||||
|
||||
|
@ -248,7 +248,7 @@ msgstr ""
|
|||
msgid "Archive"
|
||||
msgstr ""
|
||||
|
||||
#: src/dialog/photo/info.vue:162
|
||||
#: src/dialog/photo/info.vue:168
|
||||
msgid "Archived"
|
||||
msgstr ""
|
||||
|
||||
|
@ -319,7 +319,7 @@ msgstr ""
|
|||
msgid "Camera"
|
||||
msgstr ""
|
||||
|
||||
#: src/dialog/photo/info.vue:67
|
||||
#: src/dialog/photo/info.vue:73
|
||||
msgid "Camera Serial"
|
||||
msgstr ""
|
||||
|
||||
|
@ -375,7 +375,7 @@ msgstr ""
|
|||
msgid "Change Status"
|
||||
msgstr ""
|
||||
|
||||
#: src/dialog/photo/info.vue:154
|
||||
#: src/dialog/photo/info.vue:160
|
||||
msgid "Checked"
|
||||
msgstr ""
|
||||
|
||||
|
@ -411,7 +411,7 @@ msgid "Connect"
|
|||
msgstr ""
|
||||
|
||||
#: src/dialog/webdav.vue:4
|
||||
#: src/pages/settings/sync.vue:45
|
||||
#: src/pages/settings/sync.vue:42
|
||||
msgid "Connect via WebDAV"
|
||||
msgstr ""
|
||||
|
||||
|
@ -474,7 +474,7 @@ msgstr ""
|
|||
msgid "Create album"
|
||||
msgstr ""
|
||||
|
||||
#: src/dialog/photo/info.vue:130
|
||||
#: src/dialog/photo/info.vue:136
|
||||
msgid "Created"
|
||||
msgstr ""
|
||||
|
||||
|
@ -619,7 +619,7 @@ msgstr ""
|
|||
msgid "Edit Photo"
|
||||
msgstr ""
|
||||
|
||||
#: src/dialog/photo/info.vue:146
|
||||
#: src/dialog/photo/info.vue:152
|
||||
msgid "Edited"
|
||||
msgstr ""
|
||||
|
||||
|
@ -682,7 +682,7 @@ msgstr ""
|
|||
msgid "Fast"
|
||||
msgstr ""
|
||||
|
||||
#: src/dialog/photo/info.vue:74
|
||||
#: src/dialog/photo/info.vue:80
|
||||
msgid "Favorite"
|
||||
msgstr ""
|
||||
|
||||
|
@ -903,12 +903,12 @@ msgstr ""
|
|||
msgid "Language"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/settings/sync.vue:111
|
||||
#: src/pages/settings/sync.vue:113
|
||||
msgid "Last Backup"
|
||||
msgstr ""
|
||||
|
||||
#: src/dialog/photo/details.vue:443
|
||||
#: src/dialog/photo/info.vue:98
|
||||
#: src/dialog/photo/info.vue:104
|
||||
msgid "Latitude"
|
||||
msgstr ""
|
||||
|
||||
|
@ -991,7 +991,7 @@ msgid "Logs"
|
|||
msgstr ""
|
||||
|
||||
#: src/dialog/photo/details.vue:444
|
||||
#: src/dialog/photo/info.vue:106
|
||||
#: src/dialog/photo/info.vue:112
|
||||
msgid "Longitude"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1102,7 +1102,7 @@ msgstr ""
|
|||
msgid "Name too long"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/settings/sync.vue:122
|
||||
#: src/pages/settings/sync.vue:129
|
||||
#: src/resources/options.js:178
|
||||
#: src/resources/options.js:188
|
||||
msgid "Never"
|
||||
|
@ -1119,9 +1119,9 @@ msgid "Newest first"
|
|||
msgstr ""
|
||||
|
||||
#: src/dialog/photo/archive.vue:13
|
||||
#: src/dialog/photo/info.vue:160
|
||||
#: src/dialog/photo/info.vue:187
|
||||
#: src/dialog/photo/info.vue:218
|
||||
#: src/dialog/photo/info.vue:245
|
||||
#: src/dialog/photo/info.vue:214
|
||||
msgid "No"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1182,7 +1182,7 @@ msgstr ""
|
|||
msgid "Note that you can as well manage and re-index your originals manually."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/settings/sync.vue:32
|
||||
#: src/pages/settings/sync.vue:34
|
||||
msgid "Note:"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1373,7 +1373,7 @@ msgid "Primary"
|
|||
msgstr ""
|
||||
|
||||
#: src/component/navigation.vue:129
|
||||
#: src/dialog/photo/info.vue:82
|
||||
#: src/dialog/photo/info.vue:88
|
||||
#: src/routes.js:171
|
||||
msgid "Private"
|
||||
msgstr ""
|
||||
|
@ -1386,7 +1386,7 @@ msgstr ""
|
|||
msgid "Quality Filter"
|
||||
msgstr ""
|
||||
|
||||
#: src/dialog/photo/info.vue:53
|
||||
#: src/dialog/photo/info.vue:59
|
||||
msgid "Quality Score"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1444,7 +1444,7 @@ msgstr ""
|
|||
msgid "Request failed - invalid response"
|
||||
msgstr ""
|
||||
|
||||
#: src/dialog/photo/info.vue:61
|
||||
#: src/dialog/photo/info.vue:67
|
||||
msgid "Resolution"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1472,7 +1472,7 @@ msgstr ""
|
|||
msgid "Save"
|
||||
msgstr ""
|
||||
|
||||
#: src/dialog/photo/info.vue:90
|
||||
#: src/dialog/photo/info.vue:96
|
||||
msgid "Scan"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1524,7 +1524,7 @@ msgstr ""
|
|||
msgid "Selection restored"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/settings/sync.vue:108
|
||||
#: src/pages/settings/sync.vue:109
|
||||
msgid "Server"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1655,7 +1655,7 @@ msgstr ""
|
|||
msgid "Support for additional services, like Google Drive, will be added over time."
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/settings/sync.vue:110
|
||||
#: src/pages/settings/sync.vue:111
|
||||
msgid "Sync"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1664,6 +1664,7 @@ msgid "Sync raw images"
|
|||
msgstr ""
|
||||
|
||||
#: src/component/photo/list.vue:114
|
||||
#: src/dialog/photo/info.vue:53
|
||||
#: src/share/photo/list.vue:93
|
||||
msgid "Taken"
|
||||
msgstr ""
|
||||
|
@ -1699,7 +1700,7 @@ msgid "Theme"
|
|||
msgstr ""
|
||||
|
||||
#: src/dialog/webdav.vue:17
|
||||
#: src/pages/settings/sync.vue:34
|
||||
#: src/pages/settings/sync.vue:36
|
||||
msgid "This mounts the originals folder as a network drive and allows you to open, edit, and delete files from your computer or smartphone as if they were local."
|
||||
msgstr ""
|
||||
|
||||
|
@ -1769,7 +1770,7 @@ msgid "UID"
|
|||
msgstr ""
|
||||
|
||||
#: src/dialog/photo/details.vue:423
|
||||
#: src/dialog/photo/info.vue:221
|
||||
#: src/dialog/photo/info.vue:227
|
||||
#: src/model/album.js:122
|
||||
#: src/model/photo.js:399
|
||||
#: src/model/photo.js:413
|
||||
|
@ -1798,7 +1799,7 @@ msgid "Unstack"
|
|||
msgstr ""
|
||||
|
||||
#: src/dialog/photo/files.vue:120
|
||||
#: src/dialog/photo/info.vue:138
|
||||
#: src/dialog/photo/info.vue:144
|
||||
msgid "Updated"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1807,7 +1808,7 @@ msgstr ""
|
|||
#: src/dialog/upload.vue:54
|
||||
#: src/pages/library/import.vue:38
|
||||
#: src/pages/settings/general.vue:319
|
||||
#: src/pages/settings/sync.vue:109
|
||||
#: src/pages/settings/sync.vue:110
|
||||
msgid "Upload"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1885,7 +1886,7 @@ msgstr ""
|
|||
msgid "WebDAV clients can connect to PhotoPrism using the following URL:"
|
||||
msgstr ""
|
||||
|
||||
#: src/pages/settings/sync.vue:33
|
||||
#: src/pages/settings/sync.vue:35
|
||||
msgid "WebDAV clients, like Microsoft’s Windows Explorer or Apple's Finder, can connect directly to PhotoPrism."
|
||||
msgstr ""
|
||||
|
||||
|
@ -1921,9 +1922,9 @@ msgstr ""
|
|||
#: src/dialog/photo/files.vue:86
|
||||
#: src/dialog/photo/files.vue:104
|
||||
#: src/dialog/photo/files.vue:110
|
||||
#: src/dialog/photo/info.vue:159
|
||||
#: src/dialog/photo/info.vue:186
|
||||
#: src/dialog/photo/info.vue:217
|
||||
#: src/dialog/photo/info.vue:244
|
||||
#: src/dialog/photo/info.vue:213
|
||||
msgid "Yes"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import Api from "common/api";
|
||||
import MockAdapter from "axios-mock-adapter";
|
||||
|
||||
window.__CONFIG__ = {"name":"PhotoPrism","version":"200531-4684f66-Linux-x86_64-DEBUG","copyright":"(c) 2018-2020 PhotoPrism.org \u003chello@photoprism.org\u003e","flags":"public debug experimental settings","siteUrl":"http://localhost:2342/","siteTitle":"PhotoPrism","siteCaption":"Browse your life","siteDescription":"Personal Photo Management powered by Go and Google TensorFlow. Free and open-source.","siteAuthor":"Anonymous","debug":true,"readonly":false,"uploadNSFW":false,"public":true,"experimental":true,"disableSettings":false,"albumCategories":null,"albums":[],"cameras":[{"ID":2,"Slug":"olympus-c2500l","Name":"Olympus C2500L","Make":"Olympus","Model":"C2500L"},{"ID":1,"Slug":"zz","Name":"Unknown","Make":"","Model":"Unknown"}],"lenses":[{"ID":1,"Slug":"zz","Name":"Unknown","Make":"","Model":"Unknown","Type":""}],"countries":[{"ID":"de","Slug":"germany","Name":"Germany"},{"ID":"is","Slug":"iceland","Name":"Iceland"},{"ID":"zz","Slug":"zz","Name":"Unknown"}],"thumbnails":[{"Name":"fit_720","Width":720,"Height":720},{"Name":"fit_2048","Width":2048,"Height":2048},{"Name":"fit_1280","Width":1280,"Height":1024},{"Name":"fit_1920","Width":1920,"Height":1200},{"Name":"fit_2560","Width":2560,"Height":1600},{"Name":"fit_3840","Width":3840,"Height":2400}],"downloadToken":"1uhovi0e","previewToken":"static","jsHash":"0fd34136","cssHash":"2b327230","settings":{"theme":"default","language":"en","templates":{"default":"index.tmpl"},"maps":{"animate":0,"style":"streets"},"features":{"archive":true,"private":true,"review":true,"upload":true,"import":true,"files":true,"moments":true,"labels":true,"places":true,"download":true,"edit":true,"share":true,"logs":true},"import":{"path":"/","move":false},"index":{"path":"/","convert":true,"rescan":false,"group":true}},"count":{"cameras":1,"lenses":0,"countries":2,"photos":126,"videos":0,"hidden":3,"favorites":1,"private":0,"review":0,"stories":0,"albums":0,"moments":0,"months":0,"folders":0,"files":255,"places":0,"labels":13,"labelMaxPhotos":1},"pos":{"uid":"","loc":"","utc":"0001-01-01T00:00:00Z","lat":0,"lng":0},"years":[2003,2002],"colors":[{"Example":"#AB47BC","Name":"Purple","Slug":"purple"},{"Example":"#FF00FF","Name":"Magenta","Slug":"magenta"},{"Example":"#EC407A","Name":"Pink","Slug":"pink"},{"Example":"#EF5350","Name":"Red","Slug":"red"},{"Example":"#FFA726","Name":"Orange","Slug":"orange"},{"Example":"#D4AF37","Name":"Gold","Slug":"gold"},{"Example":"#FDD835","Name":"Yellow","Slug":"yellow"},{"Example":"#CDDC39","Name":"Lime","Slug":"lime"},{"Example":"#66BB6A","Name":"Green","Slug":"green"},{"Example":"#009688","Name":"Teal","Slug":"teal"},{"Example":"#00BCD4","Name":"Cyan","Slug":"cyan"},{"Example":"#2196F3","Name":"Blue","Slug":"blue"},{"Example":"#A1887F","Name":"Brown","Slug":"brown"},{"Example":"#F5F5F5","Name":"White","Slug":"white"},{"Example":"#9E9E9E","Name":"Grey","Slug":"grey"},{"Example":"#212121","Name":"Black","Slug":"black"}],"categories":[{"UID":"lqb6y631re96cper","Slug":"animal","Name":"Animal"},{"UID":"lqb6y5gvo9avdfx5","Slug":"architecture","Name":"Architecture"},{"UID":"lqb6y633nhfj1uzt","Slug":"bird","Name":"Bird"},{"UID":"lqb6y633g3hxg1aq","Slug":"farm","Name":"Farm"},{"UID":"lqb6y4i1ez9cw5bi","Slug":"nature","Name":"Nature"},{"UID":"lqb6y4f2v7dw8irs","Slug":"plant","Name":"Plant"},{"UID":"lqb6y6s2ohhmu0fn","Slug":"reptile","Name":"Reptile"},{"UID":"lqb6y6ctgsq2g2np","Slug":"water","Name":"Water"}],"clip":160,"server":{"cores":2,"routines":23,"memory":{"used":1224531272,"reserved":1416904088,"info":"Used 1.2 GB / Reserved 1.4 GB"}}};
|
||||
window.__CONFIG__ = {"name":"PhotoPrism","version":"200531-4684f66-Linux-x86_64-DEBUG","copyright":"(c) 2018-2020 PhotoPrism.org \u003chello@photoprism.org\u003e","flags":"public debug experimental settings","siteUrl":"http://localhost:2342/","siteTitle":"PhotoPrism","siteCaption":"Browse your life","siteDescription":"Personal Photo Management powered by Go and Google TensorFlow. Free and open-source.","siteAuthor":"Anonymous","debug":true,"readonly":false,"uploadNSFW":false,"public":true,"experimental":true,"disableSettings":false,"albumCategories":null,"albums":[],"cameras":[{"ID":2,"Slug":"olympus-c2500l","Name":"Olympus C2500L","Make":"Olympus","Model":"C2500L"},{"ID":1,"Slug":"zz","Name":"Unknown","Make":"","Model":"Unknown"}],"lenses":[{"ID":1,"Slug":"zz","Name":"Unknown","Make":"","Model":"Unknown","Type":""}],"countries":[{"ID":"de","Slug":"germany","Name":"Germany"},{"ID":"is","Slug":"iceland","Name":"Iceland"},{"ID":"zz","Slug":"zz","Name":"Unknown"}],"thumbs":[{"Name":"fit_720","Width":720,"Height":720},{"Name":"fit_2048","Width":2048,"Height":2048},{"Name":"fit_1280","Width":1280,"Height":1024},{"Name":"fit_1920","Width":1920,"Height":1200},{"Name":"fit_2560","Width":2560,"Height":1600},{"Name":"fit_3840","Width":3840,"Height":2400}],"downloadToken":"1uhovi0e","previewToken":"static","jsHash":"0fd34136","cssHash":"2b327230","settings":{"theme":"default","language":"en","templates":{"default":"index.tmpl"},"maps":{"animate":0,"style":"streets"},"features":{"archive":true,"private":true,"review":true,"upload":true,"import":true,"files":true,"moments":true,"labels":true,"places":true,"download":true,"edit":true,"share":true,"logs":true},"import":{"path":"/","move":false},"index":{"path":"/","convert":true,"rescan":false,"group":true}},"count":{"cameras":1,"lenses":0,"countries":2,"photos":126,"videos":0,"hidden":3,"favorites":1,"private":0,"review":0,"stories":0,"albums":0,"moments":0,"months":0,"folders":0,"files":255,"places":0,"labels":13,"labelMaxPhotos":1},"pos":{"uid":"","loc":"","utc":"0001-01-01T00:00:00Z","lat":0,"lng":0},"years":[2003,2002],"colors":[{"Example":"#AB47BC","Name":"Purple","Slug":"purple"},{"Example":"#FF00FF","Name":"Magenta","Slug":"magenta"},{"Example":"#EC407A","Name":"Pink","Slug":"pink"},{"Example":"#EF5350","Name":"Red","Slug":"red"},{"Example":"#FFA726","Name":"Orange","Slug":"orange"},{"Example":"#D4AF37","Name":"Gold","Slug":"gold"},{"Example":"#FDD835","Name":"Yellow","Slug":"yellow"},{"Example":"#CDDC39","Name":"Lime","Slug":"lime"},{"Example":"#66BB6A","Name":"Green","Slug":"green"},{"Example":"#009688","Name":"Teal","Slug":"teal"},{"Example":"#00BCD4","Name":"Cyan","Slug":"cyan"},{"Example":"#2196F3","Name":"Blue","Slug":"blue"},{"Example":"#A1887F","Name":"Brown","Slug":"brown"},{"Example":"#F5F5F5","Name":"White","Slug":"white"},{"Example":"#9E9E9E","Name":"Grey","Slug":"grey"},{"Example":"#212121","Name":"Black","Slug":"black"}],"categories":[{"UID":"lqb6y631re96cper","Slug":"animal","Name":"Animal"},{"UID":"lqb6y5gvo9avdfx5","Slug":"architecture","Name":"Architecture"},{"UID":"lqb6y633nhfj1uzt","Slug":"bird","Name":"Bird"},{"UID":"lqb6y633g3hxg1aq","Slug":"farm","Name":"Farm"},{"UID":"lqb6y4i1ez9cw5bi","Slug":"nature","Name":"Nature"},{"UID":"lqb6y4f2v7dw8irs","Slug":"plant","Name":"Plant"},{"UID":"lqb6y6s2ohhmu0fn","Slug":"reptile","Name":"Reptile"},{"UID":"lqb6y6ctgsq2g2np","Slug":"water","Name":"Water"}],"clip":160,"server":{"cores":2,"routines":23,"memory":{"used":1224531272,"reserved":1416904088,"info":"Used 1.2 GB / Reserved 1.4 GB"}}};
|
||||
|
||||
let chai = require("chai/chai");
|
||||
let assert = chai.assert;
|
||||
|
|
|
@ -2,7 +2,7 @@ import Clipboard from "common/clipboard";
|
|||
import Photo from "model/photo";
|
||||
import Album from "model/album";
|
||||
|
||||
window.__CONFIG__ = {"name":"PhotoPrism","version":"200531-4684f66-Linux-x86_64-DEBUG","copyright":"(c) 2018-2020 PhotoPrism.org \u003chello@photoprism.org\u003e","flags":"public debug experimental settings","siteUrl":"http://localhost:2342/","siteTitle":"PhotoPrism","siteCaption":"Browse your life","siteDescription":"Personal Photo Management powered by Go and Google TensorFlow. Free and open-source.","siteAuthor":"Anonymous","debug":true,"readonly":false,"uploadNSFW":false,"public":true,"experimental":true,"disableSettings":false,"albumCategories":null,"albums":[],"cameras":[{"ID":2,"Slug":"olympus-c2500l","Name":"Olympus C2500L","Make":"Olympus","Model":"C2500L"},{"ID":1,"Slug":"zz","Name":"Unknown","Make":"","Model":"Unknown"}],"lenses":[{"ID":1,"Slug":"zz","Name":"Unknown","Make":"","Model":"Unknown","Type":""}],"countries":[{"ID":"de","Slug":"germany","Name":"Germany"},{"ID":"is","Slug":"iceland","Name":"Iceland"},{"ID":"zz","Slug":"zz","Name":"Unknown"}],"thumbnails":[{"Name":"fit_720","Width":720,"Height":720},{"Name":"fit_2048","Width":2048,"Height":2048},{"Name":"fit_1280","Width":1280,"Height":1024},{"Name":"fit_1920","Width":1920,"Height":1200},{"Name":"fit_2560","Width":2560,"Height":1600},{"Name":"fit_3840","Width":3840,"Height":2400}],"downloadToken":"1uhovi0e","previewToken":"static","jsHash":"0fd34136","cssHash":"2b327230","settings":{"theme":"default","language":"en","templates":{"default":"index.tmpl"},"maps":{"animate":0,"style":"streets"},"features":{"archive":true,"private":true,"review":true,"upload":true,"import":true,"files":true,"moments":true,"labels":true,"places":true,"download":true,"edit":true,"share":true,"logs":true},"import":{"path":"/","move":false},"index":{"path":"/","convert":true,"rescan":false,"group":true}},"count":{"cameras":1,"lenses":0,"countries":2,"photos":126,"videos":0,"hidden":3,"favorites":1,"private":0,"review":0,"stories":0,"albums":0,"moments":0,"months":0,"folders":0,"files":255,"places":0,"labels":13,"labelMaxPhotos":1},"pos":{"uid":"","loc":"","utc":"0001-01-01T00:00:00Z","lat":0,"lng":0},"years":[2003,2002],"colors":[{"Example":"#AB47BC","Name":"Purple","Slug":"purple"},{"Example":"#FF00FF","Name":"Magenta","Slug":"magenta"},{"Example":"#EC407A","Name":"Pink","Slug":"pink"},{"Example":"#EF5350","Name":"Red","Slug":"red"},{"Example":"#FFA726","Name":"Orange","Slug":"orange"},{"Example":"#D4AF37","Name":"Gold","Slug":"gold"},{"Example":"#FDD835","Name":"Yellow","Slug":"yellow"},{"Example":"#CDDC39","Name":"Lime","Slug":"lime"},{"Example":"#66BB6A","Name":"Green","Slug":"green"},{"Example":"#009688","Name":"Teal","Slug":"teal"},{"Example":"#00BCD4","Name":"Cyan","Slug":"cyan"},{"Example":"#2196F3","Name":"Blue","Slug":"blue"},{"Example":"#A1887F","Name":"Brown","Slug":"brown"},{"Example":"#F5F5F5","Name":"White","Slug":"white"},{"Example":"#9E9E9E","Name":"Grey","Slug":"grey"},{"Example":"#212121","Name":"Black","Slug":"black"}],"categories":[{"UID":"lqb6y631re96cper","Slug":"animal","Name":"Animal"},{"UID":"lqb6y5gvo9avdfx5","Slug":"architecture","Name":"Architecture"},{"UID":"lqb6y633nhfj1uzt","Slug":"bird","Name":"Bird"},{"UID":"lqb6y633g3hxg1aq","Slug":"farm","Name":"Farm"},{"UID":"lqb6y4i1ez9cw5bi","Slug":"nature","Name":"Nature"},{"UID":"lqb6y4f2v7dw8irs","Slug":"plant","Name":"Plant"},{"UID":"lqb6y6s2ohhmu0fn","Slug":"reptile","Name":"Reptile"},{"UID":"lqb6y6ctgsq2g2np","Slug":"water","Name":"Water"}],"clip":160,"server":{"cores":2,"routines":23,"memory":{"used":1224531272,"reserved":1416904088,"info":"Used 1.2 GB / Reserved 1.4 GB"}}};
|
||||
window.__CONFIG__ = {"name":"PhotoPrism","version":"200531-4684f66-Linux-x86_64-DEBUG","copyright":"(c) 2018-2020 PhotoPrism.org \u003chello@photoprism.org\u003e","flags":"public debug experimental settings","siteUrl":"http://localhost:2342/","siteTitle":"PhotoPrism","siteCaption":"Browse your life","siteDescription":"Personal Photo Management powered by Go and Google TensorFlow. Free and open-source.","siteAuthor":"Anonymous","debug":true,"readonly":false,"uploadNSFW":false,"public":true,"experimental":true,"disableSettings":false,"albumCategories":null,"albums":[],"cameras":[{"ID":2,"Slug":"olympus-c2500l","Name":"Olympus C2500L","Make":"Olympus","Model":"C2500L"},{"ID":1,"Slug":"zz","Name":"Unknown","Make":"","Model":"Unknown"}],"lenses":[{"ID":1,"Slug":"zz","Name":"Unknown","Make":"","Model":"Unknown","Type":""}],"countries":[{"ID":"de","Slug":"germany","Name":"Germany"},{"ID":"is","Slug":"iceland","Name":"Iceland"},{"ID":"zz","Slug":"zz","Name":"Unknown"}],"thumbs":[{"Name":"fit_720","Width":720,"Height":720},{"Name":"fit_2048","Width":2048,"Height":2048},{"Name":"fit_1280","Width":1280,"Height":1024},{"Name":"fit_1920","Width":1920,"Height":1200},{"Name":"fit_2560","Width":2560,"Height":1600},{"Name":"fit_3840","Width":3840,"Height":2400}],"downloadToken":"1uhovi0e","previewToken":"static","jsHash":"0fd34136","cssHash":"2b327230","settings":{"theme":"default","language":"en","templates":{"default":"index.tmpl"},"maps":{"animate":0,"style":"streets"},"features":{"archive":true,"private":true,"review":true,"upload":true,"import":true,"files":true,"moments":true,"labels":true,"places":true,"download":true,"edit":true,"share":true,"logs":true},"import":{"path":"/","move":false},"index":{"path":"/","convert":true,"rescan":false,"group":true}},"count":{"cameras":1,"lenses":0,"countries":2,"photos":126,"videos":0,"hidden":3,"favorites":1,"private":0,"review":0,"stories":0,"albums":0,"moments":0,"months":0,"folders":0,"files":255,"places":0,"labels":13,"labelMaxPhotos":1},"pos":{"uid":"","loc":"","utc":"0001-01-01T00:00:00Z","lat":0,"lng":0},"years":[2003,2002],"colors":[{"Example":"#AB47BC","Name":"Purple","Slug":"purple"},{"Example":"#FF00FF","Name":"Magenta","Slug":"magenta"},{"Example":"#EC407A","Name":"Pink","Slug":"pink"},{"Example":"#EF5350","Name":"Red","Slug":"red"},{"Example":"#FFA726","Name":"Orange","Slug":"orange"},{"Example":"#D4AF37","Name":"Gold","Slug":"gold"},{"Example":"#FDD835","Name":"Yellow","Slug":"yellow"},{"Example":"#CDDC39","Name":"Lime","Slug":"lime"},{"Example":"#66BB6A","Name":"Green","Slug":"green"},{"Example":"#009688","Name":"Teal","Slug":"teal"},{"Example":"#00BCD4","Name":"Cyan","Slug":"cyan"},{"Example":"#2196F3","Name":"Blue","Slug":"blue"},{"Example":"#A1887F","Name":"Brown","Slug":"brown"},{"Example":"#F5F5F5","Name":"White","Slug":"white"},{"Example":"#9E9E9E","Name":"Grey","Slug":"grey"},{"Example":"#212121","Name":"Black","Slug":"black"}],"categories":[{"UID":"lqb6y631re96cper","Slug":"animal","Name":"Animal"},{"UID":"lqb6y5gvo9avdfx5","Slug":"architecture","Name":"Architecture"},{"UID":"lqb6y633nhfj1uzt","Slug":"bird","Name":"Bird"},{"UID":"lqb6y633g3hxg1aq","Slug":"farm","Name":"Farm"},{"UID":"lqb6y4i1ez9cw5bi","Slug":"nature","Name":"Nature"},{"UID":"lqb6y4f2v7dw8irs","Slug":"plant","Name":"Plant"},{"UID":"lqb6y6s2ohhmu0fn","Slug":"reptile","Name":"Reptile"},{"UID":"lqb6y6ctgsq2g2np","Slug":"water","Name":"Water"}],"clip":160,"server":{"cores":2,"routines":23,"memory":{"used":1224531272,"reserved":1416904088,"info":"Used 1.2 GB / Reserved 1.4 GB"}}};
|
||||
|
||||
let chai = require("chai/chai");
|
||||
let assert = chai.assert;
|
||||
|
|
|
@ -33,7 +33,7 @@ window.__CONFIG__ = {
|
|||
"Slug": "iceland",
|
||||
"Name": "Iceland"
|
||||
}, {"ID": "zz", "Slug": "zz", "Name": "Unknown"}],
|
||||
"thumbnails": [{"Name": "fit_720", "Width": 720, "Height": 720}, {
|
||||
"thumbs": [{"Name": "fit_720", "Width": 720, "Height": 720}, {
|
||||
"Name": "fit_2048",
|
||||
"Width": 2048,
|
||||
"Height": 2048
|
||||
|
|
|
@ -30,7 +30,7 @@ window.__CONFIG__ = {
|
|||
"Slug": "iceland",
|
||||
"Name": "Iceland"
|
||||
}, {"ID": "zz", "Slug": "zz", "Name": "Unknown"}],
|
||||
"thumbnails": [{"Name": "fit_720", "Width": 720, "Height": 720}, {
|
||||
"thumbs": [{"Name": "fit_720", "Width": 720, "Height": 720}, {
|
||||
"Name": "fit_2048",
|
||||
"Width": 2048,
|
||||
"Height": 2048
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import Util from "common/util";
|
||||
import MockAdapter from "axios-mock-adapter";
|
||||
|
||||
window.__CONFIG__ = {"name":"PhotoPrism","version":"200531-4684f66-Linux-x86_64-DEBUG","copyright":"(c) 2018-2020 PhotoPrism.org \u003chello@photoprism.org\u003e","flags":"public debug experimental settings","siteUrl":"http://localhost:2342/","siteTitle":"PhotoPrism","siteCaption":"Browse your life","siteDescription":"Personal Photo Management powered by Go and Google TensorFlow. Free and open-source.","siteAuthor":"Anonymous","debug":true,"readonly":false,"uploadNSFW":false,"public":true,"experimental":true,"disableSettings":false,"albumCategories":null,"albums":[],"cameras":[{"ID":2,"Slug":"olympus-c2500l","Name":"Olympus C2500L","Make":"Olympus","Model":"C2500L"},{"ID":1,"Slug":"zz","Name":"Unknown","Make":"","Model":"Unknown"}],"lenses":[{"ID":1,"Slug":"zz","Name":"Unknown","Make":"","Model":"Unknown","Type":""}],"countries":[{"ID":"de","Slug":"germany","Name":"Germany"},{"ID":"is","Slug":"iceland","Name":"Iceland"},{"ID":"zz","Slug":"zz","Name":"Unknown"}],"thumbnails":[{"Name":"fit_720","Width":720,"Height":720},{"Name":"fit_2048","Width":2048,"Height":2048},{"Name":"fit_1280","Width":1280,"Height":1024},{"Name":"fit_1920","Width":1920,"Height":1200},{"Name":"fit_2560","Width":2560,"Height":1600},{"Name":"fit_3840","Width":3840,"Height":2400}],"downloadToken":"1uhovi0e","previewToken":"static","jsHash":"0fd34136","cssHash":"2b327230","settings":{"theme":"default","language":"en","templates":{"default":"index.tmpl"},"maps":{"animate":0,"style":"streets"},"features":{"archive":true,"private":true,"review":true,"upload":true,"import":true,"files":true,"moments":true,"labels":true,"places":true,"download":true,"edit":true,"share":true,"logs":true},"import":{"path":"/","move":false},"index":{"path":"/","convert":true,"rescan":false,"group":true}},"count":{"cameras":1,"lenses":0,"countries":2,"photos":126,"videos":0,"hidden":3,"favorites":1,"private":0,"review":0,"stories":0,"albums":0,"moments":0,"months":0,"folders":0,"files":255,"places":0,"labels":13,"labelMaxPhotos":1},"pos":{"uid":"","loc":"","utc":"0001-01-01T00:00:00Z","lat":0,"lng":0},"years":[2003,2002],"colors":[{"Example":"#AB47BC","Name":"Purple","Slug":"purple"},{"Example":"#FF00FF","Name":"Magenta","Slug":"magenta"},{"Example":"#EC407A","Name":"Pink","Slug":"pink"},{"Example":"#EF5350","Name":"Red","Slug":"red"},{"Example":"#FFA726","Name":"Orange","Slug":"orange"},{"Example":"#D4AF37","Name":"Gold","Slug":"gold"},{"Example":"#FDD835","Name":"Yellow","Slug":"yellow"},{"Example":"#CDDC39","Name":"Lime","Slug":"lime"},{"Example":"#66BB6A","Name":"Green","Slug":"green"},{"Example":"#009688","Name":"Teal","Slug":"teal"},{"Example":"#00BCD4","Name":"Cyan","Slug":"cyan"},{"Example":"#2196F3","Name":"Blue","Slug":"blue"},{"Example":"#A1887F","Name":"Brown","Slug":"brown"},{"Example":"#F5F5F5","Name":"White","Slug":"white"},{"Example":"#9E9E9E","Name":"Grey","Slug":"grey"},{"Example":"#212121","Name":"Black","Slug":"black"}],"categories":[{"UID":"lqb6y631re96cper","Slug":"animal","Name":"Animal"},{"UID":"lqb6y5gvo9avdfx5","Slug":"architecture","Name":"Architecture"},{"UID":"lqb6y633nhfj1uzt","Slug":"bird","Name":"Bird"},{"UID":"lqb6y633g3hxg1aq","Slug":"farm","Name":"Farm"},{"UID":"lqb6y4i1ez9cw5bi","Slug":"nature","Name":"Nature"},{"UID":"lqb6y4f2v7dw8irs","Slug":"plant","Name":"Plant"},{"UID":"lqb6y6s2ohhmu0fn","Slug":"reptile","Name":"Reptile"},{"UID":"lqb6y6ctgsq2g2np","Slug":"water","Name":"Water"}],"clip":160,"server":{"cores":2,"routines":23,"memory":{"used":1224531272,"reserved":1416904088,"info":"Used 1.2 GB / Reserved 1.4 GB"}}};
|
||||
window.__CONFIG__ = {"name":"PhotoPrism","version":"200531-4684f66-Linux-x86_64-DEBUG","copyright":"(c) 2018-2020 PhotoPrism.org \u003chello@photoprism.org\u003e","flags":"public debug experimental settings","siteUrl":"http://localhost:2342/","siteTitle":"PhotoPrism","siteCaption":"Browse your life","siteDescription":"Personal Photo Management powered by Go and Google TensorFlow. Free and open-source.","siteAuthor":"Anonymous","debug":true,"readonly":false,"uploadNSFW":false,"public":true,"experimental":true,"disableSettings":false,"albumCategories":null,"albums":[],"cameras":[{"ID":2,"Slug":"olympus-c2500l","Name":"Olympus C2500L","Make":"Olympus","Model":"C2500L"},{"ID":1,"Slug":"zz","Name":"Unknown","Make":"","Model":"Unknown"}],"lenses":[{"ID":1,"Slug":"zz","Name":"Unknown","Make":"","Model":"Unknown","Type":""}],"countries":[{"ID":"de","Slug":"germany","Name":"Germany"},{"ID":"is","Slug":"iceland","Name":"Iceland"},{"ID":"zz","Slug":"zz","Name":"Unknown"}],"thumbs":[{"Name":"fit_720","Width":720,"Height":720},{"Name":"fit_2048","Width":2048,"Height":2048},{"Name":"fit_1280","Width":1280,"Height":1024},{"Name":"fit_1920","Width":1920,"Height":1200},{"Name":"fit_2560","Width":2560,"Height":1600},{"Name":"fit_3840","Width":3840,"Height":2400}],"downloadToken":"1uhovi0e","previewToken":"static","jsHash":"0fd34136","cssHash":"2b327230","settings":{"theme":"default","language":"en","templates":{"default":"index.tmpl"},"maps":{"animate":0,"style":"streets"},"features":{"archive":true,"private":true,"review":true,"upload":true,"import":true,"files":true,"moments":true,"labels":true,"places":true,"download":true,"edit":true,"share":true,"logs":true},"import":{"path":"/","move":false},"index":{"path":"/","convert":true,"rescan":false,"group":true}},"count":{"cameras":1,"lenses":0,"countries":2,"photos":126,"videos":0,"hidden":3,"favorites":1,"private":0,"review":0,"stories":0,"albums":0,"moments":0,"months":0,"folders":0,"files":255,"places":0,"labels":13,"labelMaxPhotos":1},"pos":{"uid":"","loc":"","utc":"0001-01-01T00:00:00Z","lat":0,"lng":0},"years":[2003,2002],"colors":[{"Example":"#AB47BC","Name":"Purple","Slug":"purple"},{"Example":"#FF00FF","Name":"Magenta","Slug":"magenta"},{"Example":"#EC407A","Name":"Pink","Slug":"pink"},{"Example":"#EF5350","Name":"Red","Slug":"red"},{"Example":"#FFA726","Name":"Orange","Slug":"orange"},{"Example":"#D4AF37","Name":"Gold","Slug":"gold"},{"Example":"#FDD835","Name":"Yellow","Slug":"yellow"},{"Example":"#CDDC39","Name":"Lime","Slug":"lime"},{"Example":"#66BB6A","Name":"Green","Slug":"green"},{"Example":"#009688","Name":"Teal","Slug":"teal"},{"Example":"#00BCD4","Name":"Cyan","Slug":"cyan"},{"Example":"#2196F3","Name":"Blue","Slug":"blue"},{"Example":"#A1887F","Name":"Brown","Slug":"brown"},{"Example":"#F5F5F5","Name":"White","Slug":"white"},{"Example":"#9E9E9E","Name":"Grey","Slug":"grey"},{"Example":"#212121","Name":"Black","Slug":"black"}],"categories":[{"UID":"lqb6y631re96cper","Slug":"animal","Name":"Animal"},{"UID":"lqb6y5gvo9avdfx5","Slug":"architecture","Name":"Architecture"},{"UID":"lqb6y633nhfj1uzt","Slug":"bird","Name":"Bird"},{"UID":"lqb6y633g3hxg1aq","Slug":"farm","Name":"Farm"},{"UID":"lqb6y4i1ez9cw5bi","Slug":"nature","Name":"Nature"},{"UID":"lqb6y4f2v7dw8irs","Slug":"plant","Name":"Plant"},{"UID":"lqb6y6s2ohhmu0fn","Slug":"reptile","Name":"Reptile"},{"UID":"lqb6y6ctgsq2g2np","Slug":"water","Name":"Water"}],"clip":160,"server":{"cores":2,"routines":23,"memory":{"used":1224531272,"reserved":1416904088,"info":"Used 1.2 GB / Reserved 1.4 GB"}}};
|
||||
|
||||
let chai = require("chai/chai");
|
||||
let assert = chai.assert;
|
||||
|
@ -55,4 +55,4 @@ describe("common/util", () => {
|
|||
const result = Util.truncate("teststring for mocha", 5, "ng");
|
||||
assert.equal(result, "tesng");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -2,7 +2,7 @@ import Label from "model/label";
|
|||
import MockAdapter from "axios-mock-adapter";
|
||||
import Api from "common/api";
|
||||
|
||||
window.__CONFIG__ = {"name":"PhotoPrism","version":"200531-4684f66-Linux-x86_64-DEBUG","copyright":"(c) 2018-2020 PhotoPrism.org \u003chello@photoprism.org\u003e","flags":"public debug experimental settings","siteUrl":"http://localhost:2342/","siteTitle":"PhotoPrism","siteCaption":"Browse your life","siteDescription":"Personal Photo Management powered by Go and Google TensorFlow. Free and open-source.","siteAuthor":"Anonymous","debug":true,"readonly":false,"uploadNSFW":false,"public":true,"experimental":true,"disableSettings":false,"albumCategories":null,"albums":[],"cameras":[{"ID":2,"Slug":"olympus-c2500l","Name":"Olympus C2500L","Make":"Olympus","Model":"C2500L"},{"ID":1,"Slug":"zz","Name":"Unknown","Make":"","Model":"Unknown"}],"lenses":[{"ID":1,"Slug":"zz","Name":"Unknown","Make":"","Model":"Unknown","Type":""}],"countries":[{"ID":"de","Slug":"germany","Name":"Germany"},{"ID":"is","Slug":"iceland","Name":"Iceland"},{"ID":"zz","Slug":"zz","Name":"Unknown"}],"thumbnails":[{"Name":"fit_720","Width":720,"Height":720},{"Name":"fit_2048","Width":2048,"Height":2048},{"Name":"fit_1280","Width":1280,"Height":1024},{"Name":"fit_1920","Width":1920,"Height":1200},{"Name":"fit_2560","Width":2560,"Height":1600},{"Name":"fit_3840","Width":3840,"Height":2400}],"downloadToken":"1uhovi0e","previewToken":"static","jsHash":"0fd34136","cssHash":"2b327230","settings":{"theme":"default","language":"en","templates":{"default":"index.tmpl"},"maps":{"animate":0,"style":"streets"},"features":{"archive":true,"private":true,"review":true,"upload":true,"import":true,"files":true,"moments":true,"labels":true,"places":true,"download":true,"edit":true,"share":true,"logs":true},"import":{"path":"/","move":false},"index":{"path":"/","convert":true,"rescan":false,"group":true}},"count":{"cameras":1,"lenses":0,"countries":2,"photos":126,"videos":0,"hidden":3,"favorites":1,"private":0,"review":0,"stories":0,"albums":0,"moments":0,"months":0,"folders":0,"files":255,"places":0,"labels":13,"labelMaxPhotos":1},"pos":{"uid":"","loc":"","utc":"0001-01-01T00:00:00Z","lat":0,"lng":0},"years":[2003,2002],"colors":[{"Example":"#AB47BC","Name":"Purple","Slug":"purple"},{"Example":"#FF00FF","Name":"Magenta","Slug":"magenta"},{"Example":"#EC407A","Name":"Pink","Slug":"pink"},{"Example":"#EF5350","Name":"Red","Slug":"red"},{"Example":"#FFA726","Name":"Orange","Slug":"orange"},{"Example":"#D4AF37","Name":"Gold","Slug":"gold"},{"Example":"#FDD835","Name":"Yellow","Slug":"yellow"},{"Example":"#CDDC39","Name":"Lime","Slug":"lime"},{"Example":"#66BB6A","Name":"Green","Slug":"green"},{"Example":"#009688","Name":"Teal","Slug":"teal"},{"Example":"#00BCD4","Name":"Cyan","Slug":"cyan"},{"Example":"#2196F3","Name":"Blue","Slug":"blue"},{"Example":"#A1887F","Name":"Brown","Slug":"brown"},{"Example":"#F5F5F5","Name":"White","Slug":"white"},{"Example":"#9E9E9E","Name":"Grey","Slug":"grey"},{"Example":"#212121","Name":"Black","Slug":"black"}],"categories":[{"UID":"lqb6y631re96cper","Slug":"animal","Name":"Animal"},{"UID":"lqb6y5gvo9avdfx5","Slug":"architecture","Name":"Architecture"},{"UID":"lqb6y633nhfj1uzt","Slug":"bird","Name":"Bird"},{"UID":"lqb6y633g3hxg1aq","Slug":"farm","Name":"Farm"},{"UID":"lqb6y4i1ez9cw5bi","Slug":"nature","Name":"Nature"},{"UID":"lqb6y4f2v7dw8irs","Slug":"plant","Name":"Plant"},{"UID":"lqb6y6s2ohhmu0fn","Slug":"reptile","Name":"Reptile"},{"UID":"lqb6y6ctgsq2g2np","Slug":"water","Name":"Water"}],"clip":160,"server":{"cores":2,"routines":23,"memory":{"used":1224531272,"reserved":1416904088,"info":"Used 1.2 GB / Reserved 1.4 GB"}}};
|
||||
window.__CONFIG__ = {"name":"PhotoPrism","version":"200531-4684f66-Linux-x86_64-DEBUG","copyright":"(c) 2018-2020 PhotoPrism.org \u003chello@photoprism.org\u003e","flags":"public debug experimental settings","siteUrl":"http://localhost:2342/","siteTitle":"PhotoPrism","siteCaption":"Browse your life","siteDescription":"Personal Photo Management powered by Go and Google TensorFlow. Free and open-source.","siteAuthor":"Anonymous","debug":true,"readonly":false,"uploadNSFW":false,"public":true,"experimental":true,"disableSettings":false,"albumCategories":null,"albums":[],"cameras":[{"ID":2,"Slug":"olympus-c2500l","Name":"Olympus C2500L","Make":"Olympus","Model":"C2500L"},{"ID":1,"Slug":"zz","Name":"Unknown","Make":"","Model":"Unknown"}],"lenses":[{"ID":1,"Slug":"zz","Name":"Unknown","Make":"","Model":"Unknown","Type":""}],"countries":[{"ID":"de","Slug":"germany","Name":"Germany"},{"ID":"is","Slug":"iceland","Name":"Iceland"},{"ID":"zz","Slug":"zz","Name":"Unknown"}],"thumbs":[{"Name":"fit_720","Width":720,"Height":720},{"Name":"fit_2048","Width":2048,"Height":2048},{"Name":"fit_1280","Width":1280,"Height":1024},{"Name":"fit_1920","Width":1920,"Height":1200},{"Name":"fit_2560","Width":2560,"Height":1600},{"Name":"fit_3840","Width":3840,"Height":2400}],"downloadToken":"1uhovi0e","previewToken":"static","jsHash":"0fd34136","cssHash":"2b327230","settings":{"theme":"default","language":"en","templates":{"default":"index.tmpl"},"maps":{"animate":0,"style":"streets"},"features":{"archive":true,"private":true,"review":true,"upload":true,"import":true,"files":true,"moments":true,"labels":true,"places":true,"download":true,"edit":true,"share":true,"logs":true},"import":{"path":"/","move":false},"index":{"path":"/","convert":true,"rescan":false,"group":true}},"count":{"cameras":1,"lenses":0,"countries":2,"photos":126,"videos":0,"hidden":3,"favorites":1,"private":0,"review":0,"stories":0,"albums":0,"moments":0,"months":0,"folders":0,"files":255,"places":0,"labels":13,"labelMaxPhotos":1},"pos":{"uid":"","loc":"","utc":"0001-01-01T00:00:00Z","lat":0,"lng":0},"years":[2003,2002],"colors":[{"Example":"#AB47BC","Name":"Purple","Slug":"purple"},{"Example":"#FF00FF","Name":"Magenta","Slug":"magenta"},{"Example":"#EC407A","Name":"Pink","Slug":"pink"},{"Example":"#EF5350","Name":"Red","Slug":"red"},{"Example":"#FFA726","Name":"Orange","Slug":"orange"},{"Example":"#D4AF37","Name":"Gold","Slug":"gold"},{"Example":"#FDD835","Name":"Yellow","Slug":"yellow"},{"Example":"#CDDC39","Name":"Lime","Slug":"lime"},{"Example":"#66BB6A","Name":"Green","Slug":"green"},{"Example":"#009688","Name":"Teal","Slug":"teal"},{"Example":"#00BCD4","Name":"Cyan","Slug":"cyan"},{"Example":"#2196F3","Name":"Blue","Slug":"blue"},{"Example":"#A1887F","Name":"Brown","Slug":"brown"},{"Example":"#F5F5F5","Name":"White","Slug":"white"},{"Example":"#9E9E9E","Name":"Grey","Slug":"grey"},{"Example":"#212121","Name":"Black","Slug":"black"}],"categories":[{"UID":"lqb6y631re96cper","Slug":"animal","Name":"Animal"},{"UID":"lqb6y5gvo9avdfx5","Slug":"architecture","Name":"Architecture"},{"UID":"lqb6y633nhfj1uzt","Slug":"bird","Name":"Bird"},{"UID":"lqb6y633g3hxg1aq","Slug":"farm","Name":"Farm"},{"UID":"lqb6y4i1ez9cw5bi","Slug":"nature","Name":"Nature"},{"UID":"lqb6y4f2v7dw8irs","Slug":"plant","Name":"Plant"},{"UID":"lqb6y6s2ohhmu0fn","Slug":"reptile","Name":"Reptile"},{"UID":"lqb6y6ctgsq2g2np","Slug":"water","Name":"Water"}],"clip":160,"server":{"cores":2,"routines":23,"memory":{"used":1224531272,"reserved":1416904088,"info":"Used 1.2 GB / Reserved 1.4 GB"}}};
|
||||
|
||||
let chai = require("chai/chai");
|
||||
let assert = chai.assert;
|
||||
|
|
|
@ -2,7 +2,7 @@ import Photo from "model/photo";
|
|||
import MockAdapter from "axios-mock-adapter";
|
||||
import Api from "common/api";
|
||||
|
||||
window.__CONFIG__ = {"name":"PhotoPrism","version":"200531-4684f66-Linux-x86_64-DEBUG","copyright":"(c) 2018-2020 PhotoPrism.org \u003chello@photoprism.org\u003e","flags":"public debug experimental settings","siteUrl":"http://localhost:2342/","siteTitle":"PhotoPrism","siteCaption":"Browse your life","siteDescription":"Personal Photo Management powered by Go and Google TensorFlow. Free and open-source.","siteAuthor":"Anonymous","debug":true,"readonly":false,"uploadNSFW":false,"public":true,"experimental":true,"disableSettings":false,"albumCategories":null,"albums":[],"cameras":[{"ID":2,"Slug":"olympus-c2500l","Name":"Olympus C2500L","Make":"Olympus","Model":"C2500L"},{"ID":1,"Slug":"zz","Name":"Unknown","Make":"","Model":"Unknown"}],"lenses":[{"ID":1,"Slug":"zz","Name":"Unknown","Make":"","Model":"Unknown","Type":""}],"countries":[{"ID":"de","Slug":"germany","Name":"Germany"},{"ID":"is","Slug":"iceland","Name":"Iceland"},{"ID":"zz","Slug":"zz","Name":"Unknown"}],"thumbnails":[{"Name":"fit_720","Width":720,"Height":720},{"Name":"fit_2048","Width":2048,"Height":2048},{"Name":"fit_1280","Width":1280,"Height":1024},{"Name":"fit_1920","Width":1920,"Height":1200},{"Name":"fit_2560","Width":2560,"Height":1600},{"Name":"fit_3840","Width":3840,"Height":2400}],"downloadToken":"1uhovi0e","previewToken":"static","jsHash":"0fd34136","cssHash":"2b327230","settings":{"theme":"default","language":"en","templates":{"default":"index.tmpl"},"maps":{"animate":0,"style":"streets"},"features":{"archive":true,"private":true,"review":true,"upload":true,"import":true,"files":true,"moments":true,"labels":true,"places":true,"download":true,"edit":true,"share":true,"logs":true},"import":{"path":"/","move":false},"index":{"path":"/","convert":true,"rescan":false,"group":true}},"count":{"cameras":1,"lenses":0,"countries":2,"photos":126,"videos":0,"hidden":3,"favorites":1,"private":0,"review":0,"stories":0,"albums":0,"moments":0,"months":0,"folders":0,"files":255,"places":0,"labels":13,"labelMaxPhotos":1},"pos":{"uid":"","loc":"","utc":"0001-01-01T00:00:00Z","lat":0,"lng":0},"years":[2003,2002],"colors":[{"Example":"#AB47BC","Name":"Purple","Slug":"purple"},{"Example":"#FF00FF","Name":"Magenta","Slug":"magenta"},{"Example":"#EC407A","Name":"Pink","Slug":"pink"},{"Example":"#EF5350","Name":"Red","Slug":"red"},{"Example":"#FFA726","Name":"Orange","Slug":"orange"},{"Example":"#D4AF37","Name":"Gold","Slug":"gold"},{"Example":"#FDD835","Name":"Yellow","Slug":"yellow"},{"Example":"#CDDC39","Name":"Lime","Slug":"lime"},{"Example":"#66BB6A","Name":"Green","Slug":"green"},{"Example":"#009688","Name":"Teal","Slug":"teal"},{"Example":"#00BCD4","Name":"Cyan","Slug":"cyan"},{"Example":"#2196F3","Name":"Blue","Slug":"blue"},{"Example":"#A1887F","Name":"Brown","Slug":"brown"},{"Example":"#F5F5F5","Name":"White","Slug":"white"},{"Example":"#9E9E9E","Name":"Grey","Slug":"grey"},{"Example":"#212121","Name":"Black","Slug":"black"}],"categories":[{"UID":"lqb6y631re96cper","Slug":"animal","Name":"Animal"},{"UID":"lqb6y5gvo9avdfx5","Slug":"architecture","Name":"Architecture"},{"UID":"lqb6y633nhfj1uzt","Slug":"bird","Name":"Bird"},{"UID":"lqb6y633g3hxg1aq","Slug":"farm","Name":"Farm"},{"UID":"lqb6y4i1ez9cw5bi","Slug":"nature","Name":"Nature"},{"UID":"lqb6y4f2v7dw8irs","Slug":"plant","Name":"Plant"},{"UID":"lqb6y6s2ohhmu0fn","Slug":"reptile","Name":"Reptile"},{"UID":"lqb6y6ctgsq2g2np","Slug":"water","Name":"Water"}],"clip":160,"server":{"cores":2,"routines":23,"memory":{"used":1224531272,"reserved":1416904088,"info":"Used 1.2 GB / Reserved 1.4 GB"}}};
|
||||
window.__CONFIG__ = {"name":"PhotoPrism","version":"200531-4684f66-Linux-x86_64-DEBUG","copyright":"(c) 2018-2020 PhotoPrism.org \u003chello@photoprism.org\u003e","flags":"public debug experimental settings","siteUrl":"http://localhost:2342/","siteTitle":"PhotoPrism","siteCaption":"Browse your life","siteDescription":"Personal Photo Management powered by Go and Google TensorFlow. Free and open-source.","siteAuthor":"Anonymous","debug":true,"readonly":false,"uploadNSFW":false,"public":true,"experimental":true,"disableSettings":false,"albumCategories":null,"albums":[],"cameras":[{"ID":2,"Slug":"olympus-c2500l","Name":"Olympus C2500L","Make":"Olympus","Model":"C2500L"},{"ID":1,"Slug":"zz","Name":"Unknown","Make":"","Model":"Unknown"}],"lenses":[{"ID":1,"Slug":"zz","Name":"Unknown","Make":"","Model":"Unknown","Type":""}],"countries":[{"ID":"de","Slug":"germany","Name":"Germany"},{"ID":"is","Slug":"iceland","Name":"Iceland"},{"ID":"zz","Slug":"zz","Name":"Unknown"}],"thumbs":[{"Name":"fit_720","Width":720,"Height":720},{"Name":"fit_2048","Width":2048,"Height":2048},{"Name":"fit_1280","Width":1280,"Height":1024},{"Name":"fit_1920","Width":1920,"Height":1200},{"Name":"fit_2560","Width":2560,"Height":1600},{"Name":"fit_3840","Width":3840,"Height":2400}],"downloadToken":"1uhovi0e","previewToken":"static","jsHash":"0fd34136","cssHash":"2b327230","settings":{"theme":"default","language":"en","templates":{"default":"index.tmpl"},"maps":{"animate":0,"style":"streets"},"features":{"archive":true,"private":true,"review":true,"upload":true,"import":true,"files":true,"moments":true,"labels":true,"places":true,"download":true,"edit":true,"share":true,"logs":true},"import":{"path":"/","move":false},"index":{"path":"/","convert":true,"rescan":false,"group":true}},"count":{"cameras":1,"lenses":0,"countries":2,"photos":126,"videos":0,"hidden":3,"favorites":1,"private":0,"review":0,"stories":0,"albums":0,"moments":0,"months":0,"folders":0,"files":255,"places":0,"labels":13,"labelMaxPhotos":1},"pos":{"uid":"","loc":"","utc":"0001-01-01T00:00:00Z","lat":0,"lng":0},"years":[2003,2002],"colors":[{"Example":"#AB47BC","Name":"Purple","Slug":"purple"},{"Example":"#FF00FF","Name":"Magenta","Slug":"magenta"},{"Example":"#EC407A","Name":"Pink","Slug":"pink"},{"Example":"#EF5350","Name":"Red","Slug":"red"},{"Example":"#FFA726","Name":"Orange","Slug":"orange"},{"Example":"#D4AF37","Name":"Gold","Slug":"gold"},{"Example":"#FDD835","Name":"Yellow","Slug":"yellow"},{"Example":"#CDDC39","Name":"Lime","Slug":"lime"},{"Example":"#66BB6A","Name":"Green","Slug":"green"},{"Example":"#009688","Name":"Teal","Slug":"teal"},{"Example":"#00BCD4","Name":"Cyan","Slug":"cyan"},{"Example":"#2196F3","Name":"Blue","Slug":"blue"},{"Example":"#A1887F","Name":"Brown","Slug":"brown"},{"Example":"#F5F5F5","Name":"White","Slug":"white"},{"Example":"#9E9E9E","Name":"Grey","Slug":"grey"},{"Example":"#212121","Name":"Black","Slug":"black"}],"categories":[{"UID":"lqb6y631re96cper","Slug":"animal","Name":"Animal"},{"UID":"lqb6y5gvo9avdfx5","Slug":"architecture","Name":"Architecture"},{"UID":"lqb6y633nhfj1uzt","Slug":"bird","Name":"Bird"},{"UID":"lqb6y633g3hxg1aq","Slug":"farm","Name":"Farm"},{"UID":"lqb6y4i1ez9cw5bi","Slug":"nature","Name":"Nature"},{"UID":"lqb6y4f2v7dw8irs","Slug":"plant","Name":"Plant"},{"UID":"lqb6y6s2ohhmu0fn","Slug":"reptile","Name":"Reptile"},{"UID":"lqb6y6ctgsq2g2np","Slug":"water","Name":"Water"}],"clip":160,"server":{"cores":2,"routines":23,"memory":{"used":1224531272,"reserved":1416904088,"info":"Used 1.2 GB / Reserved 1.4 GB"}}};
|
||||
|
||||
let chai = require("chai/chai");
|
||||
let assert = chai.assert;
|
||||
|
|
|
@ -2,12 +2,10 @@ package api
|
|||
|
||||
import (
|
||||
"archive/zip"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
@ -20,7 +18,6 @@ import (
|
|||
"github.com/photoprism/photoprism/internal/photoprism"
|
||||
"github.com/photoprism/photoprism/internal/query"
|
||||
"github.com/photoprism/photoprism/internal/service"
|
||||
"github.com/photoprism/photoprism/internal/thumb"
|
||||
"github.com/photoprism/photoprism/pkg/fs"
|
||||
"github.com/photoprism/photoprism/pkg/rnd"
|
||||
|
||||
|
@ -503,115 +500,3 @@ func DownloadAlbum(router *gin.RouterGroup) {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
// GET /api/v1/albums/:uid/t/:token/:type
|
||||
//
|
||||
// Parameters:
|
||||
// uid: string Album UID
|
||||
// type: string Thumbnail type, see photoprism.ThumbnailTypes
|
||||
func AlbumThumbnail(router *gin.RouterGroup) {
|
||||
router.GET("/albums/:uid/t/:token/:type", func(c *gin.Context) {
|
||||
if InvalidPreviewToken(c) {
|
||||
c.Data(http.StatusForbidden, "image/svg+xml", albumIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
conf := service.Config()
|
||||
typeName := c.Param("type")
|
||||
uid := c.Param("uid")
|
||||
|
||||
thumbType, ok := thumb.Types[typeName]
|
||||
|
||||
if !ok {
|
||||
log.Errorf("album-thumbnail: invalid type %s", typeName)
|
||||
c.Data(http.StatusOK, "image/svg+xml", albumIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
cache := service.Cache()
|
||||
cacheKey := fmt.Sprintf("album-thumbnail:%s:%s", uid, typeName)
|
||||
|
||||
if cacheData, err := cache.Get(cacheKey); err == nil {
|
||||
log.Debugf("cache hit for %s [%s]", cacheKey, time.Since(start))
|
||||
|
||||
var cached ThumbCache
|
||||
|
||||
if err := json.Unmarshal(cacheData, &cached); err != nil {
|
||||
log.Errorf("album-thumbnail: %s not found", uid)
|
||||
c.Data(http.StatusOK, "image/svg+xml", albumIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
if !fs.FileExists(cached.FileName) {
|
||||
log.Errorf("album-thumbnail: %s not found", uid)
|
||||
c.Data(http.StatusOK, "image/svg+xml", albumIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
if c.Query("download") != "" {
|
||||
c.FileAttachment(cached.FileName, cached.ShareName)
|
||||
} else {
|
||||
c.File(cached.FileName)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
f, err := query.AlbumCoverByUID(uid)
|
||||
|
||||
if err != nil {
|
||||
log.Debugf("album-thumbnail: no photos yet, using generic image for %s", uid)
|
||||
c.Data(http.StatusOK, "image/svg+xml", albumIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
fileName := photoprism.FileName(f.FileRoot, f.FileName)
|
||||
|
||||
if !fs.FileExists(fileName) {
|
||||
log.Errorf("album-thumbnail: could not find original for %s", fileName)
|
||||
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("album-thumbnail: %s is missing", txt.Quote(f.FileName))
|
||||
logError("album-thumbnail", f.Update("FileMissing", true))
|
||||
return
|
||||
}
|
||||
|
||||
// Use original file if thumb size exceeds limit, see https://github.com/photoprism/photoprism/issues/157
|
||||
if thumbType.ExceedsLimit() && c.Query("download") == "" {
|
||||
log.Debugf("album-thumbnail: using original, size exceeds limit (width %d, height %d)", thumbType.Width, thumbType.Height)
|
||||
c.File(fileName)
|
||||
return
|
||||
}
|
||||
|
||||
var thumbnail string
|
||||
|
||||
if conf.ThumbUncached() || thumbType.OnDemand() {
|
||||
thumbnail, err = thumb.FromFile(fileName, f.FileHash, conf.ThumbPath(), thumbType.Width, thumbType.Height, thumbType.Options...)
|
||||
} else {
|
||||
thumbnail, err = thumb.FromCache(fileName, f.FileHash, conf.ThumbPath(), thumbType.Width, thumbType.Height, thumbType.Options...)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("album: %s", err)
|
||||
c.Data(http.StatusOK, "image/svg+xml", photoIconSvg)
|
||||
return
|
||||
} else if thumbnail == "" {
|
||||
log.Errorf("album-thumbnail: %s has empty thumb name - bug?", filepath.Base(fileName))
|
||||
c.Data(http.StatusOK, "image/svg+xml", albumIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
if cached, err := json.Marshal(ThumbCache{thumbnail, f.ShareFileName()}); err == nil {
|
||||
logError("album-thumbnail", cache.Set(cacheKey, cached))
|
||||
log.Debugf("cached %s [%s]", cacheKey, time.Since(start))
|
||||
}
|
||||
|
||||
if c.Query("download") != "" {
|
||||
c.FileAttachment(thumbnail, f.ShareFileName())
|
||||
} else {
|
||||
c.File(thumbnail)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -266,25 +266,3 @@ func TestDownloadAlbum(t *testing.T) {
|
|||
assert.Equal(t, http.StatusOK, r.Code)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAlbumThumbnail(t *testing.T) {
|
||||
t.Run("invalid type", func(t *testing.T) {
|
||||
app, router, conf := NewApiTest()
|
||||
AlbumThumbnail(router)
|
||||
r := PerformRequest(app, "GET", "/api/v1/albums/at9lxuqxpogaaba7/t/"+conf.PreviewToken()+"/xxx")
|
||||
|
||||
assert.Equal(t, http.StatusOK, r.Code)
|
||||
})
|
||||
t.Run("album has no photo (because is not existing)", func(t *testing.T) {
|
||||
app, router, conf := NewApiTest()
|
||||
AlbumThumbnail(router)
|
||||
r := PerformRequest(app, "GET", "/api/v1/albums/987-986435/t/"+conf.PreviewToken()+"/tile_500")
|
||||
assert.Equal(t, http.StatusOK, r.Code)
|
||||
})
|
||||
t.Run("album: could not find original", func(t *testing.T) {
|
||||
app, router, conf := NewApiTest()
|
||||
AlbumThumbnail(router)
|
||||
r := PerformRequest(app, "GET", "/api/v1/albums/at9lxuqxpogaaba8/t/"+conf.PreviewToken()+"/tile_500")
|
||||
assert.Equal(t, http.StatusOK, r.Code)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,12 +1,8 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
|
@ -15,11 +11,7 @@ import (
|
|||
"github.com/photoprism/photoprism/internal/event"
|
||||
"github.com/photoprism/photoprism/internal/form"
|
||||
"github.com/photoprism/photoprism/internal/i18n"
|
||||
"github.com/photoprism/photoprism/internal/photoprism"
|
||||
"github.com/photoprism/photoprism/internal/query"
|
||||
"github.com/photoprism/photoprism/internal/service"
|
||||
"github.com/photoprism/photoprism/internal/thumb"
|
||||
"github.com/photoprism/photoprism/pkg/fs"
|
||||
"github.com/photoprism/photoprism/pkg/txt"
|
||||
)
|
||||
|
||||
|
@ -168,117 +160,3 @@ func DislikeLabel(router *gin.RouterGroup) {
|
|||
c.JSON(http.StatusOK, http.Response{})
|
||||
})
|
||||
}
|
||||
|
||||
// GET /api/v1/labels/:uid/t/:token/:type
|
||||
//
|
||||
// Parameters:
|
||||
// uid: string Label UID
|
||||
// type: string Thumbnail type, see photoprism.ThumbnailTypes
|
||||
func LabelThumbnail(router *gin.RouterGroup) {
|
||||
router.GET("/labels/:uid/t/:token/:type", func(c *gin.Context) {
|
||||
if InvalidPreviewToken(c) {
|
||||
c.Data(http.StatusForbidden, "image/svg+xml", labelIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
conf := service.Config()
|
||||
typeName := c.Param("type")
|
||||
uid := c.Param("uid")
|
||||
|
||||
thumbType, ok := thumb.Types[typeName]
|
||||
|
||||
if !ok {
|
||||
log.Errorf("label-thumbnail: invalid type %s", txt.Quote(typeName))
|
||||
c.Data(http.StatusOK, "image/svg+xml", labelIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
cache := service.Cache()
|
||||
cacheKey := fmt.Sprintf("label-thumbnail:%s:%s", uid, typeName)
|
||||
|
||||
if cacheData, err := cache.Get(cacheKey); err == nil {
|
||||
log.Debugf("cache hit for %s [%s]", cacheKey, time.Since(start))
|
||||
|
||||
var cached ThumbCache
|
||||
|
||||
if err := json.Unmarshal(cacheData, &cached); err != nil {
|
||||
log.Errorf("label-thumbnail: %s not found", uid)
|
||||
c.Data(http.StatusOK, "image/svg+xml", labelIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
if !fs.FileExists(cached.FileName) {
|
||||
log.Errorf("label-thumbnail: %s not found", uid)
|
||||
c.Data(http.StatusOK, "image/svg+xml", labelIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
if c.Query("download") != "" {
|
||||
c.FileAttachment(cached.FileName, cached.ShareName)
|
||||
} else {
|
||||
c.File(cached.FileName)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
f, err := query.LabelThumbByUID(uid)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
c.Data(http.StatusOK, "image/svg+xml", labelIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
fileName := photoprism.FileName(f.FileRoot, f.FileName)
|
||||
|
||||
if !fs.FileExists(fileName) {
|
||||
log.Errorf("label-thumbnail: file %s is missing", txt.Quote(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.
|
||||
logError("label-thumbnail", f.Update("FileMissing", true))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Use original file if thumb size exceeds limit, see https://github.com/photoprism/photoprism/issues/157
|
||||
if thumbType.ExceedsLimit() {
|
||||
log.Debugf("label-thumbnail: using original, size exceeds limit (width %d, height %d)", thumbType.Width, thumbType.Height)
|
||||
|
||||
c.File(fileName)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
var thumbnail string
|
||||
|
||||
if conf.ThumbUncached() || thumbType.OnDemand() {
|
||||
thumbnail, err = thumb.FromFile(fileName, f.FileHash, conf.ThumbPath(), thumbType.Width, thumbType.Height, thumbType.Options...)
|
||||
} else {
|
||||
thumbnail, err = thumb.FromCache(fileName, f.FileHash, conf.ThumbPath(), thumbType.Width, thumbType.Height, thumbType.Options...)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("label-thumbnail: %s", err)
|
||||
c.Data(http.StatusOK, "image/svg+xml", labelIconSvg)
|
||||
return
|
||||
} else if thumbnail == "" {
|
||||
log.Errorf("label-thumbnail: %s has empty thumb name - bug?", filepath.Base(fileName))
|
||||
c.Data(http.StatusOK, "image/svg+xml", labelIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
if cached, err := json.Marshal(ThumbCache{thumbnail, f.ShareFileName()}); err == nil {
|
||||
logError("label-thumbnail", cache.Set(cacheKey, cached))
|
||||
log.Debugf("cached %s [%s]", cacheKey, time.Since(start))
|
||||
}
|
||||
|
||||
if c.Query("download") != "" {
|
||||
c.FileAttachment(thumbnail, f.ShareFileName())
|
||||
} else {
|
||||
c.File(thumbnail)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -108,25 +108,3 @@ func TestDislikeLabel(t *testing.T) {
|
|||
assert.Equal(t, "false", val2.String())
|
||||
})
|
||||
}
|
||||
|
||||
func TestLabelThumbnail(t *testing.T) {
|
||||
t.Run("invalid type", func(t *testing.T) {
|
||||
app, router, conf := NewApiTest()
|
||||
LabelThumbnail(router)
|
||||
r := PerformRequest(app, "GET", "/api/v1/labels/lt9k3pw1wowuy3c2/t/"+conf.PreviewToken()+"/xxx")
|
||||
assert.Equal(t, http.StatusOK, r.Code)
|
||||
})
|
||||
t.Run("invalid label", func(t *testing.T) {
|
||||
app, router, conf := NewApiTest()
|
||||
LabelThumbnail(router)
|
||||
r := PerformRequest(app, "GET", "/api/v1/labels/xxx/t/"+conf.PreviewToken()+"/tile_500")
|
||||
|
||||
assert.Equal(t, http.StatusOK, r.Code)
|
||||
})
|
||||
t.Run("could not find original", func(t *testing.T) {
|
||||
app, router, conf := NewApiTest()
|
||||
LabelThumbnail(router)
|
||||
r := PerformRequest(app, "GET", "/api/v1/labels/lt9k3pw1wowuy3c3/t/"+conf.PreviewToken()+"/tile_500")
|
||||
assert.Equal(t, http.StatusOK, r.Code)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -329,85 +329,3 @@ func PhotoFilePrimary(router *gin.RouterGroup) {
|
|||
c.JSON(http.StatusOK, p)
|
||||
})
|
||||
}
|
||||
|
||||
// POST /api/v1/photos/:uid/files/:file_uid/unstack
|
||||
//
|
||||
// Parameters:
|
||||
// uid: string Photo UID as returned by the API
|
||||
// file_uid: string File UID as returned by the API
|
||||
func PhotoFileUnstack(router *gin.RouterGroup) {
|
||||
router.POST("/photos/:uid/files/:file_uid/unstack", func(c *gin.Context) {
|
||||
s := Auth(SessionID(c), acl.ResourcePhotos, acl.ActionUpdate)
|
||||
|
||||
if s.Invalid() {
|
||||
AbortUnauthorized(c)
|
||||
return
|
||||
}
|
||||
|
||||
photoUID := c.Param("uid")
|
||||
fileUID := c.Param("file_uid")
|
||||
|
||||
file, err := query.FileByUID(fileUID)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("photo: %s (unstack)", err)
|
||||
AbortEntityNotFound(c)
|
||||
return
|
||||
}
|
||||
|
||||
if file.FilePrimary {
|
||||
log.Errorf("photo: can't unstack primary file")
|
||||
AbortBadRequest(c)
|
||||
return
|
||||
}
|
||||
|
||||
existingPhoto := *file.Photo
|
||||
newPhoto := entity.NewPhoto()
|
||||
|
||||
if err := newPhoto.Create(); err != nil {
|
||||
log.Errorf("photo: %s (unstack)", err.Error())
|
||||
AbortSaveFailed(c)
|
||||
return
|
||||
}
|
||||
|
||||
file.Photo = &newPhoto
|
||||
file.PhotoID = newPhoto.ID
|
||||
file.PhotoUID = newPhoto.PhotoUID
|
||||
|
||||
if err := file.Save(); err != nil {
|
||||
log.Errorf("photo: %s (unstack)", err.Error())
|
||||
AbortSaveFailed(c)
|
||||
return
|
||||
}
|
||||
|
||||
fileName := photoprism.FileName(file.FileRoot, file.FileName)
|
||||
|
||||
f, err := photoprism.NewMediaFile(fileName)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("photo: %s (unstack)", err)
|
||||
AbortEntityNotFound(c)
|
||||
return
|
||||
}
|
||||
|
||||
if err := service.Index().MediaFile(f, photoprism.IndexOptions{Rescan: true}, existingPhoto.OriginalName).Error; err != nil {
|
||||
log.Errorf("photo: %s (unstack)", err)
|
||||
AbortSaveFailed(c)
|
||||
return
|
||||
}
|
||||
|
||||
PublishPhotoEvent(EntityCreated, file.PhotoUID, c)
|
||||
PublishPhotoEvent(EntityUpdated, photoUID, c)
|
||||
|
||||
event.SuccessMsg(i18n.MsgFileUnstacked)
|
||||
|
||||
p, err := query.PhotoPreloadByUID(photoUID)
|
||||
|
||||
if err != nil {
|
||||
AbortEntityNotFound(c)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, p)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,162 +0,0 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/photoprism/photoprism/internal/photoprism"
|
||||
"github.com/photoprism/photoprism/internal/query"
|
||||
"github.com/photoprism/photoprism/internal/service"
|
||||
"github.com/photoprism/photoprism/internal/thumb"
|
||||
"github.com/photoprism/photoprism/pkg/fs"
|
||||
"github.com/photoprism/photoprism/pkg/txt"
|
||||
)
|
||||
|
||||
type ThumbCache struct {
|
||||
FileName string
|
||||
ShareName string
|
||||
}
|
||||
|
||||
type ByteCache struct {
|
||||
Data []byte
|
||||
}
|
||||
|
||||
// GET /api/v1/t/:hash/:token/:type
|
||||
//
|
||||
// Parameters:
|
||||
// hash: string The file hash as returned by the search API
|
||||
// type: string Thumbnail type, see photoprism.ThumbnailTypes
|
||||
func GetThumbnail(router *gin.RouterGroup) {
|
||||
router.GET("/t/:hash/:token/:type", func(c *gin.Context) {
|
||||
if InvalidPreviewToken(c) {
|
||||
c.Data(http.StatusForbidden, "image/svg+xml", brokenIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
conf := service.Config()
|
||||
fileHash := c.Param("hash")
|
||||
typeName := c.Param("type")
|
||||
|
||||
thumbType, ok := thumb.Types[typeName]
|
||||
|
||||
if !ok {
|
||||
log.Errorf("thumbnail: invalid type %s", txt.Quote(typeName))
|
||||
c.Data(http.StatusOK, "image/svg+xml", photoIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
cache := service.Cache()
|
||||
cacheKey := fmt.Sprintf("thumbnail:%s:%s", fileHash, typeName)
|
||||
|
||||
if cacheData, err := cache.Get(cacheKey); err == nil {
|
||||
log.Debugf("cache hit for %s [%s]", cacheKey, time.Since(start))
|
||||
|
||||
var cached ThumbCache
|
||||
|
||||
if err := json.Unmarshal(cacheData, &cached); err != nil {
|
||||
log.Errorf("thumbnail: %s not found", fileHash)
|
||||
c.Data(http.StatusOK, "image/svg+xml", albumIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
if !fs.FileExists(cached.FileName) {
|
||||
log.Errorf("thumbnail: %s not found", fileHash)
|
||||
c.Data(http.StatusOK, "image/svg+xml", brokenIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
if c.Query("download") != "" {
|
||||
c.FileAttachment(cached.FileName, cached.ShareName)
|
||||
} else {
|
||||
c.File(cached.FileName)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
f, err := query.FileByHash(fileHash)
|
||||
|
||||
if err != nil {
|
||||
c.Data(http.StatusOK, "image/svg+xml", photoIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
// Find fallback if file is not a JPEG image.
|
||||
if f.NoJPEG() {
|
||||
f, err = query.FileByPhotoUID(f.PhotoUID)
|
||||
|
||||
if err != nil {
|
||||
c.Data(http.StatusOK, "image/svg+xml", fileIconSvg)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Return SVG icon as placeholder if file has errors.
|
||||
if f.FileError != "" {
|
||||
c.Data(http.StatusOK, "image/svg+xml", brokenIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
fileName := photoprism.FileName(f.FileRoot, f.FileName)
|
||||
|
||||
if !fs.FileExists(fileName) {
|
||||
log.Errorf("thumbnail: file %s is missing", txt.Quote(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("thumbnail", f.Update("FileMissing", true))
|
||||
|
||||
if f.AllFilesMissing() {
|
||||
log.Infof("thumbnail: deleting photo, all files missing for %s", txt.Quote(f.FileName))
|
||||
|
||||
logError("thumbnail", f.RelatedPhoto().Delete(false))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Use original file if thumb size exceeds limit, see https://github.com/photoprism/photoprism/issues/157
|
||||
if thumbType.ExceedsLimit() && c.Query("download") == "" {
|
||||
log.Debugf("thumbnail: using original, size exceeds limit (width %d, height %d)", thumbType.Width, thumbType.Height)
|
||||
|
||||
c.File(fileName)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
var thumbnail string
|
||||
|
||||
if conf.ThumbUncached() || thumbType.OnDemand() {
|
||||
thumbnail, err = thumb.FromFile(fileName, f.FileHash, conf.ThumbPath(), thumbType.Width, thumbType.Height, thumbType.Options...)
|
||||
} else {
|
||||
thumbnail, err = thumb.FromCache(fileName, f.FileHash, conf.ThumbPath(), thumbType.Width, thumbType.Height, thumbType.Options...)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("thumbnail: %s", err)
|
||||
c.Data(http.StatusOK, "image/svg+xml", brokenIconSvg)
|
||||
return
|
||||
} else if thumbnail == "" {
|
||||
log.Errorf("thumbnail: %s has empty thumb name - bug?", filepath.Base(fileName))
|
||||
c.Data(http.StatusOK, "image/svg+xml", brokenIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
// Cache thumbnail filename.
|
||||
if cached, err := json.Marshal(ThumbCache{thumbnail, f.ShareFileName()}); err == nil {
|
||||
logError("thumbnail", cache.Set(cacheKey, cached))
|
||||
log.Debugf("cached %s [%s]", cacheKey, time.Since(start))
|
||||
}
|
||||
|
||||
if c.Query("download") != "" {
|
||||
c.FileAttachment(thumbnail, f.ShareFileName())
|
||||
} else {
|
||||
c.File(thumbnail)
|
||||
}
|
||||
})
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGetThumbnail(t *testing.T) {
|
||||
t.Run("invalid type", func(t *testing.T) {
|
||||
app, router, conf := NewApiTest()
|
||||
GetThumbnail(router)
|
||||
r := PerformRequest(app, "GET", "/api/v1/t/1/"+conf.PreviewToken()+"/xxx")
|
||||
|
||||
assert.Equal(t, http.StatusOK, r.Code)
|
||||
})
|
||||
t.Run("invalid hash", func(t *testing.T) {
|
||||
app, router, conf := NewApiTest()
|
||||
GetThumbnail(router)
|
||||
r := PerformRequest(app, "GET", "/api/v1/t/1/"+conf.PreviewToken()+"/tile_500")
|
||||
|
||||
assert.Equal(t, http.StatusOK, r.Code)
|
||||
})
|
||||
t.Run("could not find original", func(t *testing.T) {
|
||||
app, router, conf := NewApiTest()
|
||||
GetThumbnail(router)
|
||||
r := PerformRequest(app, "GET", "/api/v1/t/2cad9168fa6acc5c5c2965ddf6ec465ca42fd818/"+conf.PreviewToken()+"/tile_500")
|
||||
assert.Equal(t, http.StatusOK, r.Code)
|
||||
})
|
||||
}
|
96
internal/api/photo_unstack.go
Normal file
96
internal/api/photo_unstack.go
Normal file
|
@ -0,0 +1,96 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/photoprism/photoprism/internal/acl"
|
||||
"github.com/photoprism/photoprism/internal/entity"
|
||||
"github.com/photoprism/photoprism/internal/event"
|
||||
"github.com/photoprism/photoprism/internal/i18n"
|
||||
"github.com/photoprism/photoprism/internal/photoprism"
|
||||
"github.com/photoprism/photoprism/internal/query"
|
||||
"github.com/photoprism/photoprism/internal/service"
|
||||
)
|
||||
|
||||
// POST /api/v1/photos/:uid/files/:file_uid/unstack
|
||||
//
|
||||
// Parameters:
|
||||
// uid: string Photo UID as returned by the API
|
||||
// file_uid: string File UID as returned by the API
|
||||
func PhotoFileUnstack(router *gin.RouterGroup) {
|
||||
router.POST("/photos/:uid/files/:file_uid/unstack", func(c *gin.Context) {
|
||||
s := Auth(SessionID(c), acl.ResourcePhotos, acl.ActionUpdate)
|
||||
|
||||
if s.Invalid() {
|
||||
AbortUnauthorized(c)
|
||||
return
|
||||
}
|
||||
|
||||
photoUID := c.Param("uid")
|
||||
fileUID := c.Param("file_uid")
|
||||
|
||||
file, err := query.FileByUID(fileUID)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("photo: %s (unstack)", err)
|
||||
AbortEntityNotFound(c)
|
||||
return
|
||||
}
|
||||
|
||||
if file.FilePrimary {
|
||||
log.Errorf("photo: can't unstack primary file")
|
||||
AbortBadRequest(c)
|
||||
return
|
||||
}
|
||||
|
||||
existingPhoto := *file.Photo
|
||||
newPhoto := entity.NewPhoto()
|
||||
|
||||
if err := newPhoto.Create(); err != nil {
|
||||
log.Errorf("photo: %s (unstack)", err.Error())
|
||||
AbortSaveFailed(c)
|
||||
return
|
||||
}
|
||||
|
||||
file.Photo = &newPhoto
|
||||
file.PhotoID = newPhoto.ID
|
||||
file.PhotoUID = newPhoto.PhotoUID
|
||||
|
||||
if err := file.Save(); err != nil {
|
||||
log.Errorf("photo: %s (unstack)", err.Error())
|
||||
AbortSaveFailed(c)
|
||||
return
|
||||
}
|
||||
|
||||
fileName := photoprism.FileName(file.FileRoot, file.FileName)
|
||||
|
||||
f, err := photoprism.NewMediaFile(fileName)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("photo: %s (unstack)", err)
|
||||
AbortEntityNotFound(c)
|
||||
return
|
||||
}
|
||||
|
||||
if err := service.Index().MediaFile(f, photoprism.IndexOptions{Rescan: true}, existingPhoto.OriginalName).Error; err != nil {
|
||||
log.Errorf("photo: %s (unstack)", err)
|
||||
AbortSaveFailed(c)
|
||||
return
|
||||
}
|
||||
|
||||
PublishPhotoEvent(EntityCreated, file.PhotoUID, c)
|
||||
PublishPhotoEvent(EntityUpdated, photoUID, c)
|
||||
|
||||
event.SuccessMsg(i18n.MsgFileUnstacked)
|
||||
|
||||
p, err := query.PhotoPreloadByUID(photoUID)
|
||||
|
||||
if err != nil {
|
||||
AbortEntityNotFound(c)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, p)
|
||||
})
|
||||
}
|
391
internal/api/thumbs.go
Normal file
391
internal/api/thumbs.go
Normal file
|
@ -0,0 +1,391 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/photoprism/photoprism/internal/photoprism"
|
||||
"github.com/photoprism/photoprism/internal/query"
|
||||
"github.com/photoprism/photoprism/internal/service"
|
||||
"github.com/photoprism/photoprism/internal/thumb"
|
||||
"github.com/photoprism/photoprism/pkg/fs"
|
||||
"github.com/photoprism/photoprism/pkg/txt"
|
||||
)
|
||||
|
||||
type ThumbCache struct {
|
||||
FileName string
|
||||
ShareName string
|
||||
}
|
||||
|
||||
type ByteCache struct {
|
||||
Data []byte
|
||||
}
|
||||
|
||||
// GET /api/v1/t/:hash/:token/:type
|
||||
//
|
||||
// Parameters:
|
||||
// hash: string file hash as returned by the search API
|
||||
// token: string security token (see config)
|
||||
// type: string thumb type, see photoprism.ThumbnailTypes
|
||||
func GetThumb(router *gin.RouterGroup) {
|
||||
router.GET("/t/:hash/:token/:type", func(c *gin.Context) {
|
||||
if InvalidPreviewToken(c) {
|
||||
c.Data(http.StatusForbidden, "image/svg+xml", brokenIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
conf := service.Config()
|
||||
fileHash := c.Param("hash")
|
||||
typeName := c.Param("type")
|
||||
|
||||
thumbType, ok := thumb.Types[typeName]
|
||||
|
||||
if !ok {
|
||||
log.Errorf("thumbs: invalid type %s", txt.Quote(typeName))
|
||||
c.Data(http.StatusOK, "image/svg+xml", photoIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
cache := service.Cache()
|
||||
cacheKey := fmt.Sprintf("thumbs:%s:%s", fileHash, typeName)
|
||||
|
||||
if cacheData, err := cache.Get(cacheKey); err == nil {
|
||||
log.Debugf("cache hit for %s [%s]", cacheKey, time.Since(start))
|
||||
|
||||
var cached ThumbCache
|
||||
|
||||
if err := json.Unmarshal(cacheData, &cached); err != nil {
|
||||
log.Errorf("thumbs: %s not found", fileHash)
|
||||
c.Data(http.StatusOK, "image/svg+xml", albumIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
if !fs.FileExists(cached.FileName) {
|
||||
log.Errorf("thumbs: %s not found", fileHash)
|
||||
c.Data(http.StatusOK, "image/svg+xml", brokenIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
if c.Query("download") != "" {
|
||||
c.FileAttachment(cached.FileName, cached.ShareName)
|
||||
} else {
|
||||
c.File(cached.FileName)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
f, err := query.FileByHash(fileHash)
|
||||
|
||||
if err != nil {
|
||||
c.Data(http.StatusOK, "image/svg+xml", photoIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
// Find fallback if file is not a JPEG image.
|
||||
if f.NoJPEG() {
|
||||
f, err = query.FileByPhotoUID(f.PhotoUID)
|
||||
|
||||
if err != nil {
|
||||
c.Data(http.StatusOK, "image/svg+xml", fileIconSvg)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// Return SVG icon as placeholder if file has errors.
|
||||
if f.FileError != "" {
|
||||
c.Data(http.StatusOK, "image/svg+xml", brokenIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
fileName := photoprism.FileName(f.FileRoot, f.FileName)
|
||||
|
||||
if !fs.FileExists(fileName) {
|
||||
log.Errorf("thumbs: file %s is missing", txt.Quote(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("thumbnail", f.Update("FileMissing", true))
|
||||
|
||||
if f.AllFilesMissing() {
|
||||
log.Infof("thumbs: deleting photo, all files missing for %s", txt.Quote(f.FileName))
|
||||
|
||||
logError("thumbnail", f.RelatedPhoto().Delete(false))
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Use original file if thumb size exceeds limit, see https://github.com/photoprism/photoprism/issues/157
|
||||
if thumbType.ExceedsLimit() && c.Query("download") == "" {
|
||||
log.Debugf("thumbs: using original, size exceeds limit (width %d, height %d)", thumbType.Width, thumbType.Height)
|
||||
|
||||
c.File(fileName)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
var thumbnail string
|
||||
|
||||
if conf.ThumbUncached() || thumbType.OnDemand() {
|
||||
thumbnail, err = thumb.FromFile(fileName, f.FileHash, conf.ThumbPath(), thumbType.Width, thumbType.Height, thumbType.Options...)
|
||||
} else {
|
||||
thumbnail, err = thumb.FromCache(fileName, f.FileHash, conf.ThumbPath(), thumbType.Width, thumbType.Height, thumbType.Options...)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("thumbs: %s", err)
|
||||
c.Data(http.StatusOK, "image/svg+xml", brokenIconSvg)
|
||||
return
|
||||
} else if thumbnail == "" {
|
||||
log.Errorf("thumbs: %s has empty thumb name - bug?", filepath.Base(fileName))
|
||||
c.Data(http.StatusOK, "image/svg+xml", brokenIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
// Cache thumbnail filename.
|
||||
if cached, err := json.Marshal(ThumbCache{thumbnail, f.ShareFileName()}); err == nil {
|
||||
logError("thumbnail", cache.Set(cacheKey, cached))
|
||||
log.Debugf("cached %s [%s]", cacheKey, time.Since(start))
|
||||
}
|
||||
|
||||
if c.Query("download") != "" {
|
||||
c.FileAttachment(thumbnail, f.ShareFileName())
|
||||
} else {
|
||||
c.File(thumbnail)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// GET /api/v1/albums/:uid/t/:token/:type
|
||||
//
|
||||
// Parameters:
|
||||
// uid: string album uid
|
||||
// token: string security token (see config)
|
||||
// type: string thumb type, see photoprism.ThumbnailTypes
|
||||
func AlbumThumb(router *gin.RouterGroup) {
|
||||
router.GET("/albums/:uid/t/:token/:type", func(c *gin.Context) {
|
||||
if InvalidPreviewToken(c) {
|
||||
c.Data(http.StatusForbidden, "image/svg+xml", albumIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
conf := service.Config()
|
||||
typeName := c.Param("type")
|
||||
uid := c.Param("uid")
|
||||
|
||||
thumbType, ok := thumb.Types[typeName]
|
||||
|
||||
if !ok {
|
||||
log.Errorf("album-thumbs: invalid type %s", typeName)
|
||||
c.Data(http.StatusOK, "image/svg+xml", albumIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
cache := service.Cache()
|
||||
cacheKey := fmt.Sprintf("album-thumbs:%s:%s", uid, typeName)
|
||||
|
||||
if cacheData, err := cache.Get(cacheKey); err == nil {
|
||||
log.Debugf("cache hit for %s [%s]", cacheKey, time.Since(start))
|
||||
|
||||
var cached ThumbCache
|
||||
|
||||
if err := json.Unmarshal(cacheData, &cached); err != nil {
|
||||
log.Errorf("album-thumbs: %s not found", uid)
|
||||
c.Data(http.StatusOK, "image/svg+xml", albumIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
if !fs.FileExists(cached.FileName) {
|
||||
log.Errorf("album-thumbs: %s not found", uid)
|
||||
c.Data(http.StatusOK, "image/svg+xml", albumIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
if c.Query("download") != "" {
|
||||
c.FileAttachment(cached.FileName, cached.ShareName)
|
||||
} else {
|
||||
c.File(cached.FileName)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
f, err := query.AlbumCoverByUID(uid)
|
||||
|
||||
if err != nil {
|
||||
log.Debugf("album-thumbs: no photos yet, using generic image for %s", uid)
|
||||
c.Data(http.StatusOK, "image/svg+xml", albumIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
fileName := photoprism.FileName(f.FileRoot, f.FileName)
|
||||
|
||||
if !fs.FileExists(fileName) {
|
||||
log.Errorf("album-thumbs: could not find original for %s", fileName)
|
||||
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("album-thumbs: %s is missing", txt.Quote(f.FileName))
|
||||
logError("album-thumbnail", f.Update("FileMissing", true))
|
||||
return
|
||||
}
|
||||
|
||||
// Use original file if thumb size exceeds limit, see https://github.com/photoprism/photoprism/issues/157
|
||||
if thumbType.ExceedsLimit() && c.Query("download") == "" {
|
||||
log.Debugf("album-thumbs: using original, size exceeds limit (width %d, height %d)", thumbType.Width, thumbType.Height)
|
||||
c.File(fileName)
|
||||
return
|
||||
}
|
||||
|
||||
var thumbnail string
|
||||
|
||||
if conf.ThumbUncached() || thumbType.OnDemand() {
|
||||
thumbnail, err = thumb.FromFile(fileName, f.FileHash, conf.ThumbPath(), thumbType.Width, thumbType.Height, thumbType.Options...)
|
||||
} else {
|
||||
thumbnail, err = thumb.FromCache(fileName, f.FileHash, conf.ThumbPath(), thumbType.Width, thumbType.Height, thumbType.Options...)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("album: %s", err)
|
||||
c.Data(http.StatusOK, "image/svg+xml", photoIconSvg)
|
||||
return
|
||||
} else if thumbnail == "" {
|
||||
log.Errorf("album-thumbs: %s has empty thumb name - bug?", filepath.Base(fileName))
|
||||
c.Data(http.StatusOK, "image/svg+xml", albumIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
if cached, err := json.Marshal(ThumbCache{thumbnail, f.ShareFileName()}); err == nil {
|
||||
logError("album-thumbnail", cache.Set(cacheKey, cached))
|
||||
log.Debugf("cached %s [%s]", cacheKey, time.Since(start))
|
||||
}
|
||||
|
||||
if c.Query("download") != "" {
|
||||
c.FileAttachment(thumbnail, f.ShareFileName())
|
||||
} else {
|
||||
c.File(thumbnail)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// GET /api/v1/labels/:uid/t/:token/:type
|
||||
//
|
||||
// Parameters:
|
||||
// uid: string label uid
|
||||
// token: string security token (see config)
|
||||
// type: string thumb type, see photoprism.ThumbnailTypes
|
||||
func LabelThumb(router *gin.RouterGroup) {
|
||||
router.GET("/labels/:uid/t/:token/:type", func(c *gin.Context) {
|
||||
if InvalidPreviewToken(c) {
|
||||
c.Data(http.StatusForbidden, "image/svg+xml", labelIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
start := time.Now()
|
||||
conf := service.Config()
|
||||
typeName := c.Param("type")
|
||||
uid := c.Param("uid")
|
||||
|
||||
thumbType, ok := thumb.Types[typeName]
|
||||
|
||||
if !ok {
|
||||
log.Errorf("label-thumbs: invalid type %s", txt.Quote(typeName))
|
||||
c.Data(http.StatusOK, "image/svg+xml", labelIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
cache := service.Cache()
|
||||
cacheKey := fmt.Sprintf("label-thumbs:%s:%s", uid, typeName)
|
||||
|
||||
if cacheData, err := cache.Get(cacheKey); err == nil {
|
||||
log.Debugf("cache hit for %s [%s]", cacheKey, time.Since(start))
|
||||
|
||||
var cached ThumbCache
|
||||
|
||||
if err := json.Unmarshal(cacheData, &cached); err != nil {
|
||||
log.Errorf("label-thumbs: %s not found", uid)
|
||||
c.Data(http.StatusOK, "image/svg+xml", labelIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
if !fs.FileExists(cached.FileName) {
|
||||
log.Errorf("label-thumbs: %s not found", uid)
|
||||
c.Data(http.StatusOK, "image/svg+xml", labelIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
if c.Query("download") != "" {
|
||||
c.FileAttachment(cached.FileName, cached.ShareName)
|
||||
} else {
|
||||
c.File(cached.FileName)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
f, err := query.LabelThumbByUID(uid)
|
||||
|
||||
if err != nil {
|
||||
log.Errorf(err.Error())
|
||||
c.Data(http.StatusOK, "image/svg+xml", labelIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
fileName := photoprism.FileName(f.FileRoot, f.FileName)
|
||||
|
||||
if !fs.FileExists(fileName) {
|
||||
log.Errorf("label-thumbs: file %s is missing", txt.Quote(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.
|
||||
logError("label-thumbnail", f.Update("FileMissing", true))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Use original file if thumb size exceeds limit, see https://github.com/photoprism/photoprism/issues/157
|
||||
if thumbType.ExceedsLimit() {
|
||||
log.Debugf("label-thumbs: using original, size exceeds limit (width %d, height %d)", thumbType.Width, thumbType.Height)
|
||||
|
||||
c.File(fileName)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
var thumbnail string
|
||||
|
||||
if conf.ThumbUncached() || thumbType.OnDemand() {
|
||||
thumbnail, err = thumb.FromFile(fileName, f.FileHash, conf.ThumbPath(), thumbType.Width, thumbType.Height, thumbType.Options...)
|
||||
} else {
|
||||
thumbnail, err = thumb.FromCache(fileName, f.FileHash, conf.ThumbPath(), thumbType.Width, thumbType.Height, thumbType.Options...)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
log.Errorf("label-thumbs: %s", err)
|
||||
c.Data(http.StatusOK, "image/svg+xml", labelIconSvg)
|
||||
return
|
||||
} else if thumbnail == "" {
|
||||
log.Errorf("label-thumbs: %s has empty thumb name - bug?", filepath.Base(fileName))
|
||||
c.Data(http.StatusOK, "image/svg+xml", labelIconSvg)
|
||||
return
|
||||
}
|
||||
|
||||
if cached, err := json.Marshal(ThumbCache{thumbnail, f.ShareFileName()}); err == nil {
|
||||
logError("label-thumbnail", cache.Set(cacheKey, cached))
|
||||
log.Debugf("cached %s [%s]", cacheKey, time.Since(start))
|
||||
}
|
||||
|
||||
if c.Query("download") != "" {
|
||||
c.FileAttachment(thumbnail, f.ShareFileName())
|
||||
} else {
|
||||
c.File(thumbnail)
|
||||
}
|
||||
})
|
||||
}
|
75
internal/api/thumbs_test.go
Normal file
75
internal/api/thumbs_test.go
Normal file
|
@ -0,0 +1,75 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestGetThumb(t *testing.T) {
|
||||
t.Run("invalid type", func(t *testing.T) {
|
||||
app, router, conf := NewApiTest()
|
||||
GetThumb(router)
|
||||
r := PerformRequest(app, "GET", "/api/v1/t/1/"+conf.PreviewToken()+"/xxx")
|
||||
|
||||
assert.Equal(t, http.StatusOK, r.Code)
|
||||
})
|
||||
t.Run("invalid hash", func(t *testing.T) {
|
||||
app, router, conf := NewApiTest()
|
||||
GetThumb(router)
|
||||
r := PerformRequest(app, "GET", "/api/v1/t/1/"+conf.PreviewToken()+"/tile_500")
|
||||
|
||||
assert.Equal(t, http.StatusOK, r.Code)
|
||||
})
|
||||
t.Run("could not find original", func(t *testing.T) {
|
||||
app, router, conf := NewApiTest()
|
||||
GetThumb(router)
|
||||
r := PerformRequest(app, "GET", "/api/v1/t/2cad9168fa6acc5c5c2965ddf6ec465ca42fd818/"+conf.PreviewToken()+"/tile_500")
|
||||
assert.Equal(t, http.StatusOK, r.Code)
|
||||
})
|
||||
}
|
||||
|
||||
func TestAlbumThumb(t *testing.T) {
|
||||
t.Run("invalid type", func(t *testing.T) {
|
||||
app, router, conf := NewApiTest()
|
||||
AlbumThumb(router)
|
||||
r := PerformRequest(app, "GET", "/api/v1/albums/at9lxuqxpogaaba7/t/"+conf.PreviewToken()+"/xxx")
|
||||
|
||||
assert.Equal(t, http.StatusOK, r.Code)
|
||||
})
|
||||
t.Run("album has no photo (because is not existing)", func(t *testing.T) {
|
||||
app, router, conf := NewApiTest()
|
||||
AlbumThumb(router)
|
||||
r := PerformRequest(app, "GET", "/api/v1/albums/987-986435/t/"+conf.PreviewToken()+"/tile_500")
|
||||
assert.Equal(t, http.StatusOK, r.Code)
|
||||
})
|
||||
t.Run("album: could not find original", func(t *testing.T) {
|
||||
app, router, conf := NewApiTest()
|
||||
AlbumThumb(router)
|
||||
r := PerformRequest(app, "GET", "/api/v1/albums/at9lxuqxpogaaba8/t/"+conf.PreviewToken()+"/tile_500")
|
||||
assert.Equal(t, http.StatusOK, r.Code)
|
||||
})
|
||||
}
|
||||
|
||||
func TestLabelThumb(t *testing.T) {
|
||||
t.Run("invalid type", func(t *testing.T) {
|
||||
app, router, conf := NewApiTest()
|
||||
LabelThumb(router)
|
||||
r := PerformRequest(app, "GET", "/api/v1/labels/lt9k3pw1wowuy3c2/t/"+conf.PreviewToken()+"/xxx")
|
||||
assert.Equal(t, http.StatusOK, r.Code)
|
||||
})
|
||||
t.Run("invalid label", func(t *testing.T) {
|
||||
app, router, conf := NewApiTest()
|
||||
LabelThumb(router)
|
||||
r := PerformRequest(app, "GET", "/api/v1/labels/xxx/t/"+conf.PreviewToken()+"/tile_500")
|
||||
|
||||
assert.Equal(t, http.StatusOK, r.Code)
|
||||
})
|
||||
t.Run("could not find original", func(t *testing.T) {
|
||||
app, router, conf := NewApiTest()
|
||||
LabelThumb(router)
|
||||
r := PerformRequest(app, "GET", "/api/v1/labels/lt9k3pw1wowuy3c3/t/"+conf.PreviewToken()+"/tile_500")
|
||||
assert.Equal(t, http.StatusOK, r.Code)
|
||||
})
|
||||
}
|
|
@ -100,7 +100,7 @@ func configAction(ctx *cli.Context) error {
|
|||
// Places / Geocoding API configuration.
|
||||
fmt.Printf("%-25s %s\n", "geocoding-api", conf.GeoCodingApi())
|
||||
|
||||
// Thumbnails, resampling and download security token.
|
||||
// Thumbs, resampling and download security token.
|
||||
fmt.Printf("%-25s %s\n", "download-token", conf.DownloadToken())
|
||||
fmt.Printf("%-25s %s\n", "preview-token", conf.PreviewToken())
|
||||
fmt.Printf("%-25s %s\n", "thumb-filter", conf.ThumbFilter())
|
||||
|
|
|
@ -33,7 +33,7 @@ type ClientConfig struct {
|
|||
Cameras []entity.Camera `json:"cameras"`
|
||||
Lenses []entity.Lens `json:"lenses"`
|
||||
Countries []entity.Country `json:"countries"`
|
||||
Thumbnails []Thumbnail `json:"thumbnails"`
|
||||
Thumbs []Thumb `json:"thumbs"`
|
||||
DownloadToken string `json:"downloadToken"`
|
||||
PreviewToken string `json:"previewToken"`
|
||||
JSHash string `json:"jsHash"`
|
||||
|
@ -138,7 +138,7 @@ func (c *Config) PublicConfig() ClientConfig {
|
|||
ReadOnly: c.ReadOnly(),
|
||||
Public: c.Public(),
|
||||
Experimental: c.Experimental(),
|
||||
Thumbnails: Thumbnails,
|
||||
Thumbs: Thumbs,
|
||||
Colors: colors.All.List(),
|
||||
JSHash: fs.Checksum(c.BuildPath() + "/app.js"),
|
||||
CSSHash: fs.Checksum(c.BuildPath() + "/app.css"),
|
||||
|
@ -178,7 +178,7 @@ func (c *Config) GuestConfig() ClientConfig {
|
|||
Public: true,
|
||||
Experimental: false,
|
||||
Colors: colors.All.List(),
|
||||
Thumbnails: Thumbnails,
|
||||
Thumbs: Thumbs,
|
||||
DownloadToken: c.DownloadToken(),
|
||||
PreviewToken: c.PreviewToken(),
|
||||
JSHash: fs.Checksum(c.BuildPath() + "/share.js"),
|
||||
|
@ -210,7 +210,7 @@ func (c *Config) UserConfig() ClientConfig {
|
|||
Public: c.Public(),
|
||||
Experimental: c.Experimental(),
|
||||
Colors: colors.All.List(),
|
||||
Thumbnails: Thumbnails,
|
||||
Thumbs: Thumbs,
|
||||
DownloadToken: c.DownloadToken(),
|
||||
PreviewToken: c.PreviewToken(),
|
||||
JSHash: fs.Checksum(c.BuildPath() + "/app.js"),
|
||||
|
|
|
@ -37,7 +37,7 @@ func init() {
|
|||
t := thumb.Types[size]
|
||||
|
||||
if t.Public {
|
||||
Thumbnails = append(Thumbnails, Thumbnail{Size: size, Use: t.Use, Width: t.Width, Height: t.Height})
|
||||
Thumbs = append(Thumbs, Thumb{Size: size, Use: t.Use, Width: t.Width, Height: t.Height})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -314,7 +314,7 @@ func TestConfig_ClientConfig(t *testing.T) {
|
|||
assert.NotEmpty(t, cc.Name)
|
||||
assert.NotEmpty(t, cc.Version)
|
||||
assert.NotEmpty(t, cc.Copyright)
|
||||
assert.NotEmpty(t, cc.Thumbnails)
|
||||
assert.NotEmpty(t, cc.Thumbs)
|
||||
assert.NotEmpty(t, cc.JSHash)
|
||||
assert.NotEmpty(t, cc.CSSHash)
|
||||
assert.Equal(t, true, cc.Debug)
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
package config
|
||||
|
||||
// Thumbnail gives direct access to width and height for a thumbnail setting
|
||||
type Thumbnail struct {
|
||||
Size string `json:"size"`
|
||||
Use string `json:"use"`
|
||||
Width int `json:"w"`
|
||||
Height int `json:"h"`
|
||||
}
|
||||
|
||||
// Thumbnails is a list of default thumbnail size available for the app
|
||||
var Thumbnails []Thumbnail
|
12
internal/config/thumbs.go
Normal file
12
internal/config/thumbs.go
Normal file
|
@ -0,0 +1,12 @@
|
|||
package config
|
||||
|
||||
// Thumb represents thumbnail info for use in client apps.
|
||||
type Thumb struct {
|
||||
Size string `json:"size"`
|
||||
Use string `json:"use"`
|
||||
Width int `json:"w"`
|
||||
Height int `json:"h"`
|
||||
}
|
||||
|
||||
// Thumbs is a list of thumbnails for use in client apps.
|
||||
var Thumbs []Thumb
|
|
@ -29,7 +29,7 @@ func registerRoutes(router *gin.Engine, conf *config.Config) {
|
|||
api.CreateSession(v1)
|
||||
api.DeleteSession(v1)
|
||||
|
||||
api.GetThumbnail(v1)
|
||||
api.GetThumb(v1)
|
||||
api.GetDownload(v1)
|
||||
api.GetVideo(v1)
|
||||
api.CreateZip(v1)
|
||||
|
@ -64,7 +64,7 @@ func registerRoutes(router *gin.Engine, conf *config.Config) {
|
|||
api.DeleteLabelLink(v1)
|
||||
api.LikeLabel(v1)
|
||||
api.DislikeLabel(v1)
|
||||
api.LabelThumbnail(v1)
|
||||
api.LabelThumb(v1)
|
||||
|
||||
api.GetFoldersOriginals(v1)
|
||||
api.GetFoldersImport(v1)
|
||||
|
@ -93,7 +93,7 @@ func registerRoutes(router *gin.Engine, conf *config.Config) {
|
|||
api.DeleteAlbumLink(v1)
|
||||
api.LikeAlbum(v1)
|
||||
api.DislikeAlbum(v1)
|
||||
api.AlbumThumbnail(v1)
|
||||
api.AlbumThumb(v1)
|
||||
api.CloneAlbums(v1)
|
||||
api.AddPhotosToAlbum(v1)
|
||||
api.RemovePhotosFromAlbum(v1)
|
||||
|
|
Loading…
Reference in a new issue