Skip to content

Commit

Permalink
Merge pull request #1231 from tetebueno/master
Browse files Browse the repository at this point in the history
Scan photos of specific directory
  • Loading branch information
tacruc authored Dec 21, 2024
2 parents ad3d360 + 8950625 commit 9cd6204
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 88 deletions.
162 changes: 86 additions & 76 deletions lib/Command/RescanPhotos.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,84 +26,94 @@

class RescanPhotos extends Command {

protected IUserManager $userManager;
protected OutputInterface $output;
protected IManager $encryptionManager;
protected PhotofilesService $photofilesService;
protected IConfig $config;
protected IUserManager $userManager;
protected OutputInterface $output;
protected IManager $encryptionManager;
protected PhotofilesService $photofilesService;
protected IConfig $config;

public function __construct(IUserManager $userManager,
IManager $encryptionManager,
PhotofilesService $photofilesService,
IConfig $config) {
parent::__construct();
$this->userManager = $userManager;
$this->encryptionManager = $encryptionManager;
$this->photofilesService = $photofilesService;
$this->config = $config;
}
public function __construct(
IUserManager $userManager,
IManager $encryptionManager,
PhotofilesService $photofilesService,
IConfig $config) {
parent::__construct();
$this->userManager = $userManager;
$this->encryptionManager = $encryptionManager;
$this->photofilesService = $photofilesService;
$this->config = $config;
}

/**
* @return void
*/
protected function configure() {
$this->setName('maps:scan-photos')
->setDescription('Rescan photos GPS exif data')
->addArgument(
'user_id',
InputArgument::OPTIONAL,
'Rescan photos GPS exif data for the given user'
)
->addOption(
'now',
null,
InputOption::VALUE_NONE,
'Dot the rescan now and not as background jobs. Doing it now might run out of memory.'
);
}
/**
* @return void
*/
protected function configure() {
$this->setName('maps:scan-photos')
->setDescription('Rescan photos GPS exif data')
->addArgument(
'user_id',
InputArgument::OPTIONAL,
'Rescan photos GPS exif data for the given user'
)
->addArgument(
'path',
InputArgument::OPTIONAL,
'Scan photos GPS exif data for the given path under user\'s files without wiping the database.'
)
->addOption(
'now',
null,
InputOption::VALUE_NONE,
'Dot the rescan now and not as background jobs. Doing it now might run out of memory.'
);
}

/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int {
if ($this->encryptionManager->isEnabled()) {
$output->writeln('Encryption is enabled. Aborted.');
return 1;
}
$this->output = $output;
$userId = $input->getArgument('user_id');
$inBackground = !($input->getOption('now') ?? true);
if ($inBackground) {
echo "Extracting coordinates from photo is performed in a BackgroundJob \n";
}
if ($userId === null) {
$this->userManager->callForSeenUsers(function (IUser $user) use ($inBackground) {
$this->rescanUserPhotos($user->getUID(), $inBackground);
});
} else {
$user = $this->userManager->get($userId);
if ($user !== null) {
$this->rescanUserPhotos($userId, $inBackground);
}
}
return 0;
}
/**
* @param InputInterface $input
* @param OutputInterface $output
* @return int
*/
protected function execute(InputInterface $input, OutputInterface $output): int {
if ($this->encryptionManager->isEnabled()) {
$output->writeln('Encryption is enabled. Aborted.');
return 1;
}
$this->output = $output;
$userId = $input->getArgument('user_id');
$pathToScan = $input->getArgument('path');
$inBackground = !($input->getOption('now') ?? true);
if ($inBackground) {
echo "Extracting coordinates from photo is performed in a BackgroundJob \n";
}
if ($userId === null) {
$this->userManager->callForSeenUsers(function (IUser $user, string $pathToScan) use ($inBackground) {
$this->rescanUserPhotos($user->getUID(), $inBackground, $pathToScan);
});
} else {
$user = $this->userManager->get($userId);
if ($user !== null) {
$this->rescanUserPhotos($userId, $inBackground, $pathToScan);
}
}
return 0;
}

/**
* @param string $userId
* @param bool $inBackground
* @return void
* @throws \OCP\PreConditionNotMetException
*/
private function rescanUserPhotos(string $userId, bool $inBackground = true) {
echo '======== User '.$userId.' ========'."\n";
$c = 1;
foreach ($this->photofilesService->rescan($userId, $inBackground) as $path) {
echo '['.$c.'] Photo "'.$path.'" added'."\n";
$c++;
}
$this->config->setUserValue($userId, 'maps', 'installScanDone', 'yes');
}
/**
* @param string $userId
* @param bool $inBackground
* @param string $pathToScan
* @return void
* @throws \OCP\PreConditionNotMetException
*/
private function rescanUserPhotos(string $userId, bool $inBackground = true, string $pathToScan = null) {
echo '======== User ' . $userId . ' ========' . "\n";
$c = 1;
foreach ($this->photofilesService->rescan($userId, $inBackground, $pathToScan) as $path) {
echo '[' . $c . '] Photo "' . $path . '" added' . "\n";
$c++;
}
if ($pathToScan === null) {
$this->config->setUserValue($userId, 'maps', 'installScanDone', 'yes');
}
}
}
35 changes: 23 additions & 12 deletions lib/Service/PhotofilesService.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
use Psr\Log\LoggerInterface;

require_once __DIR__ . '/../../vendor/autoload.php';

use lsolesen\pel\PelDataWindow;
use lsolesen\pel\PelEntryAscii;
use lsolesen\pel\PelEntryRational;
Expand Down Expand Up @@ -71,11 +72,16 @@ public function __construct(
$this->backgroundJobCache = $this->cacheFactory->createDistributed('maps:background-jobs');
}

public function rescan($userId, $inBackground = true) {
public function rescan($userId, $inBackground = true, $pathToScan = null) {
$this->photosCache->clear($userId);
$userFolder = $this->root->getUserFolder($userId);
$photos = $this->gatherPhotoFiles($userFolder, true);
$this->photoMapper->deleteAll($userId);
if ($pathToScan === null) {
$folder = $userFolder;
$this->photoMapper->deleteAll($userId);
} else {
$folder = $userFolder->get($pathToScan);
}
$photos = $this->gatherPhotoFiles($folder, true);
foreach ($photos as $photo) {
if ($inBackground) {
$this->addPhoto($photo, $userId);
Expand Down Expand Up @@ -404,7 +410,7 @@ private function gatherPhotoFiles($folder, $recursive) {
}
try {
$notes = array_merge($notes, $this->gatherPhotoFiles($node, $recursive));
} catch (\OCP\Files\StorageNotAvailableException|\Exception $e) {
} catch (\OCP\Files\StorageNotAvailableException | \Exception $e) {
$msg = 'WARNING: Could not access ' . $node->getName();
echo($msg . "\n");
$this->logger->error($msg);
Expand Down Expand Up @@ -442,12 +448,12 @@ private function getExif($file) : ?ExifGeoData {
$exif_geo_data->validate(true);
} catch (ExifDataInvalidException $e) {
$exif_geo_data = null;
$this->logger->notice($e->getMessage(), ['code' => $e->getCode(),'path' => $path]);
$this->logger->notice($e->getMessage(), ['code' => $e->getCode(), 'path' => $path]);
} catch (ExifDataNoLocationException $e) {
$this->logger->notice($e->getMessage(), ['code' => $e->getCode(),'path' => $path]);
$this->logger->notice($e->getMessage(), ['code' => $e->getCode(), 'path' => $path]);
} catch (\Throwable $f) {
$exif_geo_data = null;
$this->logger->error($f->getMessage(), ['code' => $f->getCode(),'path' => $path]);
$this->logger->error($f->getMessage(), ['code' => $f->getCode(), 'path' => $path]);
}
return $exif_geo_data;
}
Expand Down Expand Up @@ -519,19 +525,25 @@ private function setGeolocation($pelSubIfdGps, $latitudeDegreeDecimal, $longitud
= $this->degreeDecimalToDegreeMinuteSecond(abs($longitudeDegreeDecimal));

$pelSubIfdGps->addEntry(new PelEntryAscii(
PelTag::GPS_LATITUDE_REF, $latitudeRef));
PelTag::GPS_LATITUDE_REF,
$latitudeRef
));
$pelSubIfdGps->addEntry(new PelEntryRational(
PelTag::GPS_LATITUDE,
[$latitudeDegreeMinuteSecond['degree'], 1],
[$latitudeDegreeMinuteSecond['minute'], 1],
[round($latitudeDegreeMinuteSecond['second'] * 1000), 1000]));
[round($latitudeDegreeMinuteSecond['second'] * 1000), 1000]
));
$pelSubIfdGps->addEntry(new PelEntryAscii(
PelTag::GPS_LONGITUDE_REF, $longitudeRef));
PelTag::GPS_LONGITUDE_REF,
$longitudeRef
));
$pelSubIfdGps->addEntry(new PelEntryRational(
PelTag::GPS_LONGITUDE,
[$longitudeDegreeMinuteSecond['degree'], 1],
[$longitudeDegreeMinuteSecond['minute'], 1],
[round($longitudeDegreeMinuteSecond['second'] * 1000), 1000]));
[round($longitudeDegreeMinuteSecond['second'] * 1000), 1000]
));
}

private function degreeDecimalToDegreeMinuteSecond($degreeDecimal) {
Expand All @@ -542,5 +554,4 @@ private function degreeDecimalToDegreeMinuteSecond($degreeDecimal) {
$second = $remainder * 60;
return ['degree' => $degree, 'minute' => $minute, 'second' => $second];
}

}

0 comments on commit 9cd6204

Please sign in to comment.