diff --git a/appinfo/info.xml b/appinfo/info.xml
index aecd1dbb..6a2864e8 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -102,6 +102,9 @@ The app does not send any sensitive data to cloud providers or similar services.
OCA\Recognize\Migration\InstallDeps
+
+ OCA\Recognize\Migration\MoveDefaultModelFolder
+
OCA\Recognize\Migration\RemoveDuplicateFaceDetections
diff --git a/lib/Migration/MoveDefaultModelFolder.php b/lib/Migration/MoveDefaultModelFolder.php
new file mode 100644
index 00000000..ff6cca53
--- /dev/null
+++ b/lib/Migration/MoveDefaultModelFolder.php
@@ -0,0 +1,68 @@
+
+ * @copyright Copyright (c) 2021, Marcel Klehr
+ *
+ * @author Joas Schilling
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ *
+ */
+namespace OCA\Recognize\Migration;
+
+use OCA\Recognize\Service\SettingsService;
+use OCP\Migration\IOutput;
+use OCP\Migration\IRepairStep;
+use Psr\Log\LoggerInterface;
+use function Safe\rename;
+use function Safe\scandir;
+
+final class MoveDefaultModelFolder implements IRepairStep {
+
+ public function __construct(
+ private SettingsService $settingsService,
+ private LoggerInterface $logger,
+ ) {
+ }
+
+ public function getName(): string {
+ return 'Try to move the default Model Folder';
+ }
+
+ public function run(IOutput $output): void {
+ $oldModelTargetPath = __DIR__ . '/../../models';
+ $oldModelArchivePath = __DIR__ . '/../../models.tar.gz';
+ $newPath = $this->settingsService->getSetting('models_target_path');
+ $newModelTargetPath = $newPath . '/models';
+ $newModelArchivePath = $newPath . '/models.tar.gz';
+
+ if (is_dir($oldModelTargetPath)) {
+ $filesToMove = scandir($oldModelTargetPath);
+ $filesToMove = array_filter($filesToMove, fn ($value) => $value !== '.' && $value === '..');
+ $filesToMove = array_map(fn ($value) => $oldModelTargetPath.'/'.$value, $filesToMove);
+ mkdir($newModelTargetPath);
+ foreach ($filesToMove as $file) {
+ rename($file, $newModelTargetPath.'/'.basename($file));
+ }
+ }
+
+ if (is_file($oldModelArchivePath)) {
+ rename($oldModelArchivePath, $newModelArchivePath);
+ }
+ }
+}
diff --git a/lib/Service/DownloadModelsService.php b/lib/Service/DownloadModelsService.php
index 64e42238..9f2b1d06 100644
--- a/lib/Service/DownloadModelsService.php
+++ b/lib/Service/DownloadModelsService.php
@@ -16,10 +16,12 @@
final class DownloadModelsService {
private IClientService $clientService;
private bool $isCLI;
+ private SettingsService $settingsService;
- public function __construct(IClientService $clientService, bool $isCLI) {
+ public function __construct(IClientService $clientService, bool $isCLI, SettingsService $settingsService) {
$this->clientService = $clientService;
$this->isCLI = $isCLI;
+ $this->settingsService = $settingsService;
}
/**
@@ -27,10 +29,11 @@ public function __construct(IClientService $clientService, bool $isCLI) {
* @throws \Exception
*/
public function download() : void {
- $targetPath = __DIR__ . '/../../models';
- if (file_exists($targetPath)) {
+ $targetPath = $this->settingsService->getSetting('models_target_path');
+ $modelPath = $targetPath . '/models';
+ if (file_exists($modelPath)) {
// remove models directory
- $it = new RecursiveDirectoryIterator($targetPath, FilesystemIterator::SKIP_DOTS);
+ $it = new RecursiveDirectoryIterator($modelPath, FilesystemIterator::SKIP_DOTS);
$files = new RecursiveIteratorIterator($it,
RecursiveIteratorIterator::CHILD_FIRST);
foreach ($files as $file) {
@@ -40,11 +43,11 @@ public function download() : void {
unlink($file->getRealPath());
}
}
- rmdir($targetPath);
+ rmdir($modelPath);
}
$archiveUrl = $this->getArchiveUrl($this->getNeededArchiveRef());
- $archivePath = __DIR__ . '/../../models.tar.gz';
+ $archivePath = $targetPath . '/models.tar.gz';
$timeout = $this->isCLI ? 0 : 480;
$this->clientService->newClient()->get($archiveUrl, ['sink' => $archivePath, 'timeout' => $timeout]);
$tarManager = new TAR($archivePath);
diff --git a/lib/Service/SettingsService.php b/lib/Service/SettingsService.php
index 8ea9d217..7075cdfd 100644
--- a/lib/Service/SettingsService.php
+++ b/lib/Service/SettingsService.php
@@ -61,6 +61,7 @@ final class SettingsService {
'nice_value' => '0',
'concurrency.enabled' => 'false',
'ffmpeg_binary' => '',
+ 'models_target_path' => '../../models_cache',
];
/** @var array */
@@ -94,7 +95,13 @@ final class SettingsService {
'landmarks.batchSize',
'movinet.batchSize',
'musicnn.batchSize',
- 'concurrency.enabled'
+ 'concurrency.enabled',
+ 'models_target_path',
+ 'models_archive_file',
+ ];
+
+ private const PATH_SETTINGS = [
+ 'models_target_path',
];
private IAppConfig $config;
@@ -121,6 +128,14 @@ public function getSetting(string $key): string {
if (in_array($key, self::LAZY_SETTINGS, true)) {
$lazy = true;
}
+
+ if (in_array($key, self::PATH_SETTINGS, true)) {
+ $path = $this->config->getAppValueString($key, self::DEFAULTS[$key], lazy: $lazy);
+ if (!$this->isPathAbsolute($path)) {
+ $path = __DIR__ .'/'. $path;
+ }
+ return $path;
+ }
return $this->config->getAppValueString($key, self::DEFAULTS[$key], lazy: $lazy);
}
@@ -182,6 +197,9 @@ public function setSetting(string $key, string $value): void {
if (in_array($key, self::LAZY_SETTINGS, true)) {
$lazy = true;
}
+ if (in_array($key, self::PATH_SETTINGS) && $value === '') {
+ $value = self::DEFAULTS[$key];
+ }
$this->config->setAppValueString($key, $value, lazy: $lazy);
}
@@ -195,4 +213,15 @@ public function getAll(): array {
}
return $settings;
}
+
+ private function isPathAbsolute(string $path): bool {
+ if ($path === '') {
+ return false;
+ }
+ if ($path[0] === '/') {
+ return true;
+ }
+
+ return false;
+ }
}
diff --git a/lib/Settings/AdminSettings.php b/lib/Settings/AdminSettings.php
index 31f13370..4afe42e5 100644
--- a/lib/Settings/AdminSettings.php
+++ b/lib/Settings/AdminSettings.php
@@ -28,9 +28,11 @@ public function getForm(): TemplateResponse {
$settings = $this->settingsService->getAll();
$this->initialState->provideInitialState('settings', $settings);
- $modelsPath = __DIR__ . '/../../models';
- $modelsDownloaded = file_exists($modelsPath);
+ $targetPath = $this->settingsService->getSetting('models_target_path');
+ $modelsDownloaded = file_exists($targetPath .' /models');
+ $modelsTargetPathWritable = is_writable($targetPath);
$this->initialState->provideInitialState('modelsDownloaded', $modelsDownloaded);
+ $this->initialState->provideInitialState('modelsTargetPathWritable', $modelsTargetPathWritable);
$tagsEnabled = $this->appManager->isEnabledForAnyone('systemtags');
$this->initialState->provideInitialState('tagsEnabled', $tagsEnabled);
diff --git a/package-lock.json b/package-lock.json
index 853f9c3b..61836d35 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "recognize",
- "version": "12.1.0-dev.0",
+ "version": "13.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "recognize",
- "version": "12.1.0-dev.0",
+ "version": "13.0.0",
"license": "MIT",
"dependencies": {
"@exifer/gps": "^1.0.0-beta.2",
diff --git a/src/components/ViewAdmin.vue b/src/components/ViewAdmin.vue
index bc465d77..589a6dbf 100644
--- a/src/components/ViewAdmin.vue
+++ b/src/components/ViewAdmin.vue
@@ -38,6 +38,23 @@
+
+
+ {{ t('recognize', 'The Model Target Path is Writable') }}
+
+
+ {{ t('recognize', 'Model Target Path is not Writable') }}
+
+
+
+
+
+ {{ t('recognize', 'Changing this Value will require you to redownload the Models. Also the models in the old Directory need to be deleted manually') }}
+
+
{{ t('recognize', 'The recognize_backend ExApp is installed; TaskProcessing mode is recommended.') }}
@@ -81,8 +98,8 @@
{{ t('recognize', 'Enable face recognition (groups photos by faces that appear in them; UI is in the photos app)') }}