nextcloud-custom-apps-face-.../facerecognition/lib/BackgroundJob/Tasks/AddMissingImagesTask.php
2024-09-03 09:12:12 +05:00

155 lines
5.0 KiB
PHP

<?php
/**
* @copyright Copyright (c) 2017-2020 Matias De lellis <mati86dl@gmail.com>
* @copyright Copyright (c) 2018, Branko Kokanovic <branko@kokanovic.org>
*
* @author Branko Kokanovic <branko@kokanovic.org>
*
* @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 <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\FaceRecognition\BackgroundJob\Tasks;
use OCP\IUser;
use OCP\Files\File;
use OCP\Files\Folder;
use OCA\FaceRecognition\BackgroundJob\FaceRecognitionBackgroundTask;
use OCA\FaceRecognition\BackgroundJob\FaceRecognitionContext;
use OCA\FaceRecognition\Db\Image;
use OCA\FaceRecognition\Db\ImageMapper;
use OCA\FaceRecognition\Service\FileService;
use OCA\FaceRecognition\Service\SettingsService;
/**
* Task that, for each user, crawls for all images in filesystem and insert them in database.
* This is job that normally does file watcher, but this should be done at least once,
* after app is installed (or re-enabled).
*/
class AddMissingImagesTask extends FaceRecognitionBackgroundTask {
const FULL_IMAGE_SCAN_DONE_KEY = "full_image_scan_done";
/** @var ImageMapper Image mapper */
private $imageMapper;
/** @var FileService */
private $fileService;
/** @var SettingsService Settings service */
private $settingsService;
/**
* @param ImageMapper $imageMapper Image mapper
* @param FileService $fileService File Service
* @param SettingsService $settingsService Settings Service
*/
public function __construct(ImageMapper $imageMapper,
FileService $fileService,
SettingsService $settingsService)
{
parent::__construct();
$this->imageMapper = $imageMapper;
$this->fileService = $fileService;
$this->settingsService = $settingsService;
}
/**
* @inheritdoc
*/
public function description() {
return "Crawl for missing images for each user and insert them in DB";
}
/**
* @inheritdoc
*/
public function execute(FaceRecognitionContext $context) {
$this->setContext($context);
// Check if we are called for one user only, or for all user in instance.
$insertedImages = 0;
$eligable_users = $this->context->getEligibleUsers();
foreach($eligable_users as $user) {
if (!$this->settingsService->getUserEnabled($user)) {
// Completely skip this task for this user, seems that disable analysis
$this->logInfo('Skipping image scan for user ' . $user . ' that has disabled the analysis');
continue;
}
if (!$this->context->isRunningInSyncMode() &&
$this->settingsService->getUserFullScanDone($user)) {
// Completely skip this task for this user, seems that we already did full scan for him
$this->logDebug('Skipping full image scan for user ' . $user);
continue;
}
$insertedImages += $this->addMissingImagesForUser($user, $this->settingsService->getCurrentFaceModel());
$this->settingsService->setUserFullScanDone(true, $user);
yield;
}
$this->context->propertyBag['AddMissingImagesTask_insertedImages'] = $insertedImages;
return true;
}
/**
* Crawl filesystem for a given user
*
* @param string $userId ID of the user for which to crawl images for
* @param int $model Used model
* @return int Number of missing images found
*/
private function addMissingImagesForUser(string $userId, int $model): int {
$this->logInfo(sprintf('Finding missing images for user %s', $userId));
$this->fileService->setupFS($userId);
$userFolder = $this->fileService->getUserFolder($userId);
return $this->parseUserFolder($userId, $model, $userFolder);
}
/**
* Recursively crawls given folder for a given user
*
* @param int $model Used model
* @param Folder $folder Folder to recursively search images in
* @return int Number of missing images found
*/
private function parseUserFolder(string $userId, int $model, Folder $folder): int {
$insertedImages = 0;
$nodes = $this->fileService->getPicturesFromFolder($folder);
foreach ($nodes as $file) {
$this->logDebug('Found ' . $file->getPath());
$image = new Image();
$image->setUser($userId);
$image->setFile($file->getId());
$image->setModel($model);
// todo: this check/insert logic for each image is so inefficient it hurts my mind
if ($this->imageMapper->imageExists($image) === null) {
// todo: can we have larger transaction with bulk insert?
$this->imageMapper->insert($image);
$insertedImages++;
}
}
return $insertedImages;
}
}