photos/js/photos-src_mixins_FaceCover...

1 line
14 KiB
Plaintext

{"version":3,"file":"photos-src_mixins_FaceCoverMixin_js-src_mixins_FetchFacesMixin_js-src_components_Loader_vue.js?v=aa0718fb997b48f22742","mappings":";;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;AChCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;ACrEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;ACxIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;;;;;;;AC1BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAkBA;AACA;;;;;;;;;;;;;;;ACvCA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","sources":["webpack:///photos/src/components/Loader.vue?vue&type=script&lang=js&","webpack:///photos/src/mixins/FaceCoverMixin.js","webpack:///photos/src/mixins/FetchFacesMixin.js","webpack:///photos/src/components/Loader.vue?vue&type=style&index=0&lang=scss&","webpack://photos/./src/components/Loader.vue?eb1b","webpack:///photos/src/components/Loader.vue","webpack://photos/./src/components/Loader.vue?5453","webpack:///photos/src/components/Loader.vue?vue&type=template&id=04a0d67a&"],"sourcesContent":["//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\nexport default {\n name: 'Loader'\n};","/**\n * @copyright Copyright (c) 2022 Marcel Klehr <mklehr@gmx.net>\n *\n * @author Marcel Klehr <mklehr@gmx.net>\n *\n * @license AGPL-3.0-or-later\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n *\n */\nimport { mapGetters } from 'vuex';\nimport he from 'he';\nexport default {\n name: 'FaceCoverMixin',\n computed: { ...mapGetters(['faces', 'facesFiles', 'files'])\n },\n methods: {\n getFaceCover(faceName) {\n return (this.facesFiles[faceName] || []).slice(0, 25).map(fileId => this.files[fileId]).map(file => ({ ...file,\n faceDetections: JSON.parse(he.decode(file.faceDetections))\n })) // sort larges face first\n .sort((a, b) => b.faceDetections.find(d => d.title === faceName).width - a.faceDetections.find(d => d.title === faceName).width) // sort fewest face detections first\n .sort((a, b) => a.faceDetections.length - b.faceDetections.length)[0];\n },\n\n /**\n * This will produce an inline style to apply to images\n * to zoom toward the detected face\n *\n * @param faceName\n * @return {{}|{transform: string, width: string, transformOrigin: string}}\n */\n getCoverStyle(faceName) {\n const cover = this.getFaceCover(faceName);\n\n if (!cover) {\n return {};\n }\n\n const detections = cover.faceDetections;\n const detection = detections.find(detection => detection.title === faceName); // Zoom into the picture so that the face fills the --photos-face-width box nicely\n // if the face is larger than the image, we don't zoom out (reason for the Math.max)\n\n const zoom = Math.max(1, 1 / detection.width * 0.4);\n const horizontalCenterOfFace = (detection.x + detection.width / 2) * 100;\n const verticalCenterOfFace = (detection.y + detection.height / 2) * 100;\n return {\n // We assume that the image is inside a div with width: var(--photos-face-width)\n width: '100%',\n // we translate the image so that the center of the detected face is in the center of the --photos-face-width box\n // and add the zoom\n transform: `translate(calc( var(--photos-face-width)/2 - ${horizontalCenterOfFace}% ), calc( var(--photos-face-width)/2 - ${verticalCenterOfFace}% )) scale(${zoom})`,\n // this is necessary for the zoom to zoom toward the center of the face\n transformOrigin: `${horizontalCenterOfFace}% ${verticalCenterOfFace}%`\n };\n }\n\n }\n};","/**\n * @copyright Copyright (c) 2022 Louis Chemineau <louis@chmn.me>\n *\n * @author Louis Chemineau <louis@chmn.me>\n *\n * @license AGPL-3.0-or-later\n *\n * This program is free software: you can redistribute it and/or modify\n * it under the terms of the GNU Affero General Public License as\n * published by the Free Software Foundation, either version 3 of the\n * License, or (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU Affero General Public License for more details.\n *\n * You should have received a copy of the GNU Affero General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n *\n */\nimport { mapActions, mapGetters } from 'vuex';\nimport { showError } from '@nextcloud/dialogs';\nimport { getCurrentUser } from '@nextcloud/auth';\nimport client from '../services/DavClient.js';\nimport logger from '../services/logger.js';\nimport DavRequest from '../services/DavRequest';\nimport { genFileInfo } from '../utils/fileUtils';\nimport AbortControllerMixin from './AbortControllerMixin';\nexport default {\n name: 'FetchFacesMixin',\n\n data() {\n return {\n errorFetchingFaces: null,\n loadingFaces: false,\n errorFetchingFiles: null,\n loadingFiles: false\n };\n },\n\n mixins: [AbortControllerMixin],\n\n async beforeMount() {\n this.fetchFaces();\n },\n\n computed: { ...mapGetters(['faces'])\n },\n methods: { ...mapActions(['appendFiles']),\n\n async fetchFaces() {\n if (this.loadingFaces) {\n return;\n }\n\n if (Object.keys(this.faces).length) {\n return;\n }\n\n try {\n this.loadingFaces = true;\n this.errorFetchingFaces = null;\n const faces = await client.getDirectoryContents(`/recognize/${getCurrentUser()?.uid}/faces/`, {\n signal: this.abortController.signal\n });\n this.$store.dispatch('addFaces', {\n faces\n });\n logger.debug(`[FetchFacesMixin] Fetched ${faces.length} new faces: `, faces);\n } catch (error) {\n if (error.response && error.response.status) {\n if (error.response.status === 404) {\n this.errorFetchingFaces = 404;\n } else {\n this.errorFetchingFaces = error;\n }\n }\n\n logger.error(t('photos', 'Failed to fetch faces list.'), error);\n showError(t('photos', 'Failed to fetch faces list.'));\n } finally {\n this.loadingFaces = false;\n }\n },\n\n async fetchFaceContent(faceName, force) {\n if (this.loadingFiles) {\n return;\n }\n\n if (!force && this.facesFiles[faceName] && this.facesFiles[faceName].length) {\n return;\n }\n\n try {\n this.errorFetchingFiles = null;\n this.loadingFiles = true;\n let {\n data: fetchedFiles\n } = await client.getDirectoryContents(`/recognize/${getCurrentUser()?.uid}/faces/${faceName}`, {\n data: DavRequest,\n details: true,\n signal: this.abortController.signal\n });\n fetchedFiles = fetchedFiles.map(file => genFileInfo(file)).map(file => ({ ...file,\n filename: file.realpath.replace(`/${getCurrentUser().uid}/files`, '')\n }));\n const fileIds = fetchedFiles.map(file => '' + file.fileid);\n this.appendFiles(fetchedFiles);\n\n if (fetchedFiles.length > 0) {\n await this.$store.commit('addFilesToFace', {\n faceName,\n fileIdsToAdd: fileIds\n });\n }\n\n logger.debug(`[FetchFacesMixin] Fetched ${fileIds.length} new files: `, fileIds);\n } catch (error) {\n if (error.response && error.response.status) {\n if (error.response.status === 404) {\n this.errorFetchingFiles = 404;\n } else {\n this.errorFetchingFiles = error;\n }\n } // cancelled request, moving on...\n\n\n logger.error('Error fetching face files', error);\n } finally {\n this.loadingFiles = false;\n }\n }\n\n }\n};","// Imports\nimport ___CSS_LOADER_API_NO_SOURCEMAP_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/noSourceMaps.js\";\nimport ___CSS_LOADER_API_IMPORT___ from \"../../node_modules/css-loader/dist/runtime/api.js\";\nvar ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_NO_SOURCEMAP_IMPORT___);\n// Module\n___CSS_LOADER_EXPORT___.push([module.id, \".loader {\\n display: grid;\\n height: 60px;\\n}\", \"\"]);\n// Exports\nexport default ___CSS_LOADER_EXPORT___;\n","\n import API from \"!../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js\";\n import domAPI from \"!../../node_modules/style-loader/dist/runtime/styleDomAPI.js\";\n import insertFn from \"!../../node_modules/style-loader/dist/runtime/insertBySelector.js\";\n import setAttributes from \"!../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js\";\n import insertStyleElement from \"!../../node_modules/style-loader/dist/runtime/insertStyleElement.js\";\n import styleTagTransformFn from \"!../../node_modules/style-loader/dist/runtime/styleTagTransform.js\";\n import content, * as namedExport from \"!!../../node_modules/css-loader/dist/cjs.js!../../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../../node_modules/postcss-loader/dist/cjs.js!../../node_modules/sass-loader/dist/cjs.js??clonedRuleSet-2[0].rules[0].use[3]!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./Loader.vue?vue&type=style&index=0&lang=scss&\";\n \n \n\nvar options = {};\n\noptions.styleTagTransform = styleTagTransformFn;\noptions.setAttributes = setAttributes;\n\n options.insert = insertFn.bind(null, \"head\");\n \noptions.domAPI = domAPI;\noptions.insertStyleElement = insertStyleElement;\n\nvar update = API(content, options);\n\n\n\nexport * from \"!!../../node_modules/css-loader/dist/cjs.js!../../node_modules/vue-loader/lib/loaders/stylePostLoader.js!../../node_modules/postcss-loader/dist/cjs.js!../../node_modules/sass-loader/dist/cjs.js??clonedRuleSet-2[0].rules[0].use[3]!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./Loader.vue?vue&type=style&index=0&lang=scss&\";\n export default content && content.locals ? content.locals : undefined;\n","import { render, staticRenderFns } from \"./Loader.vue?vue&type=template&id=04a0d67a&\"\nimport script from \"./Loader.vue?vue&type=script&lang=js&\"\nexport * from \"./Loader.vue?vue&type=script&lang=js&\"\nimport style0 from \"./Loader.vue?vue&type=style&index=0&lang=scss&\"\n\n\n/* normalize component */\nimport normalizer from \"!../../node_modules/vue-loader/lib/runtime/componentNormalizer.js\"\nvar component = normalizer(\n script,\n render,\n staticRenderFns,\n false,\n null,\n null,\n null\n \n)\n\n/* hot reload */\nif (module.hot) {\n var api = require(\"/home/louis/workspace/nextcloud/apps/photos/node_modules/vue-hot-reload-api/dist/index.js\")\n api.install(require('vue'))\n if (api.compatible) {\n module.hot.accept()\n if (!api.isRecorded('04a0d67a')) {\n api.createRecord('04a0d67a', component.options)\n } else {\n api.reload('04a0d67a', component.options)\n }\n module.hot.accept(\"./Loader.vue?vue&type=template&id=04a0d67a&\", function () {\n api.rerender('04a0d67a', {\n render: render,\n staticRenderFns: staticRenderFns\n })\n })\n }\n}\ncomponent.options.__file = \"src/components/Loader.vue\"\nexport default component.exports","import mod from \"-!../../node_modules/babel-loader/lib/index.js!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./Loader.vue?vue&type=script&lang=js&\"; export default mod; export * from \"-!../../node_modules/babel-loader/lib/index.js!../../node_modules/vue-loader/lib/index.js??vue-loader-options!./Loader.vue?vue&type=script&lang=js&\"","var render = function () {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\n \"div\",\n { staticClass: \"loader\" },\n [\n _vm._t(\"icon\", function () {\n return [_c(\"span\", { staticClass: \"icon-loading\" })]\n }),\n ],\n 2\n )\n}\nvar staticRenderFns = []\nrender._withStripped = true\n\nexport { render, staticRenderFns }"],"names":[],"sourceRoot":""}