Skip to content
Closed
Prev Previous commit
Next Next commit
Port metadata providers to the new API
Signed-off-by: Louis Chemineau <[email protected]>
  • Loading branch information
artonge committed Oct 19, 2023
commit 798a6b0018166e6b2d878f56685a660d723ad813
23 changes: 22 additions & 1 deletion lib/composer/composer/autoload_classmap.php
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,14 @@
'OCP\\Federation\\ICloudId' => $baseDir . '/lib/public/Federation/ICloudId.php',
'OCP\\Federation\\ICloudIdManager' => $baseDir . '/lib/public/Federation/ICloudIdManager.php',
'OCP\\Files' => $baseDir . '/lib/public/Files.php',
'OCP\\FilesMetadata\\Event\\MetadataBackgroundEvent' => $baseDir . '/lib/public/FilesMetadata/Event/MetadataBackgroundEvent.php',
'OCP\\FilesMetadata\\Event\\MetadataLiveEvent' => $baseDir . '/lib/public/FilesMetadata/Event/MetadataLiveEvent.php',
'OCP\\FilesMetadata\\Exceptions\\FilesMetadataException' => $baseDir . '/lib/public/FilesMetadata/Exceptions/FilesMetadataException.php',
'OCP\\FilesMetadata\\Exceptions\\FilesMetadataNotFoundException' => $baseDir . '/lib/public/FilesMetadata/Exceptions/FilesMetadataNotFoundException.php',
'OCP\\FilesMetadata\\Exceptions\\FilesMetadataTypeException' => $baseDir . '/lib/public/FilesMetadata/Exceptions/FilesMetadataTypeException.php',
'OCP\\FilesMetadata\\IFilesMetadataManager' => $baseDir . '/lib/public/FilesMetadata/IFilesMetadataManager.php',
'OCP\\FilesMetadata\\Model\\IFilesMetadata' => $baseDir . '/lib/public/FilesMetadata/Model/IFilesMetadata.php',
'OCP\\FilesMetadata\\Model\\IMetadataQuery' => $baseDir . '/lib/public/FilesMetadata/Model/IMetadataQuery.php',
'OCP\\Files\\AlreadyExistsException' => $baseDir . '/lib/public/Files/AlreadyExistsException.php',
'OCP\\Files\\AppData\\IAppDataFactory' => $baseDir . '/lib/public/Files/AppData/IAppDataFactory.php',
'OCP\\Files\\Cache\\AbstractCacheEvent' => $baseDir . '/lib/public/Files/Cache/AbstractCacheEvent.php',
Expand Down Expand Up @@ -1005,6 +1013,7 @@
'OC\\Core\\Command\\Encryption\\SetDefaultModule' => $baseDir . '/core/Command/Encryption/SetDefaultModule.php',
'OC\\Core\\Command\\Encryption\\ShowKeyStorageRoot' => $baseDir . '/core/Command/Encryption/ShowKeyStorageRoot.php',
'OC\\Core\\Command\\Encryption\\Status' => $baseDir . '/core/Command/Encryption/Status.php',
'OC\\Core\\Command\\FilesMetadata\\Get' => $baseDir . '/core/Command/FilesMetadata/Get.php',
'OC\\Core\\Command\\Group\\Add' => $baseDir . '/core/Command/Group/Add.php',
'OC\\Core\\Command\\Group\\AddUser' => $baseDir . '/core/Command/Group/AddUser.php',
'OC\\Core\\Command\\Group\\Delete' => $baseDir . '/core/Command/Group/Delete.php',
Expand Down Expand Up @@ -1175,6 +1184,7 @@
'OC\\Core\\Migrations\\Version28000Date20230616104802' => $baseDir . '/core/Migrations/Version28000Date20230616104802.php',
'OC\\Core\\Migrations\\Version28000Date20230728104802' => $baseDir . '/core/Migrations/Version28000Date20230728104802.php',
'OC\\Core\\Migrations\\Version28000Date20230803221055' => $baseDir . '/core/Migrations/Version28000Date20230803221055.php',
'OC\\Core\\Migrations\\Version28000Date20231004103301' => $baseDir . '/core/Migrations/Version28000Date20231004103301.php',
'OC\\Core\\Notification\\CoreNotifier' => $baseDir . '/core/Notification/CoreNotifier.php',
'OC\\Core\\Service\\LoginFlowV2Service' => $baseDir . '/core/Service/LoginFlowV2Service.php',
'OC\\DB\\Adapter' => $baseDir . '/lib/private/DB/Adapter.php',
Expand Down Expand Up @@ -1259,6 +1269,18 @@
'OC\\Federation\\CloudFederationShare' => $baseDir . '/lib/private/Federation/CloudFederationShare.php',
'OC\\Federation\\CloudId' => $baseDir . '/lib/private/Federation/CloudId.php',
'OC\\Federation\\CloudIdManager' => $baseDir . '/lib/private/Federation/CloudIdManager.php',
'OC\\FilesMetadata\\Event\\MetadataEventBase' => $baseDir . '/lib/private/FilesMetadata/Event/MetadataEventBase.php',
'OC\\FilesMetadata\\FilesMetadataManager' => $baseDir . '/lib/private/FilesMetadata/FilesMetadataManager.php',
'OC\\FilesMetadata\\Job\\UpdateSingleMetadata' => $baseDir . '/lib/private/FilesMetadata/Job/UpdateSingleMetadata.php',
'OC\\FilesMetadata\\Listener\\MetadataDelete' => $baseDir . '/lib/private/FilesMetadata/Listener/MetadataDelete.php',
'OC\\FilesMetadata\\Listener\\MetadataUpdate' => $baseDir . '/lib/private/FilesMetadata/Listener/MetadataUpdate.php',
'OC\\FilesMetadata\\Model\\FilesMetadata' => $baseDir . '/lib/private/FilesMetadata/Model/FilesMetadata.php',
'OC\\FilesMetadata\\Model\\MetadataQuery' => $baseDir . '/lib/private/FilesMetadata/Model/MetadataQuery.php',
'OC\\FilesMetadata\\Model\\MetadataValueWrapper' => $baseDir . '/lib/private/FilesMetadata/Model/MetadataValueWrapper.php',
'OC\\FilesMetadata\\Provider\\ExifMetadataProvider' => $baseDir . '/lib/private/FilesMetadata/Provider/ExifMetadataProvider.php',
'OC\\FilesMetadata\\Provider\\OriginalDateTimeMetadataProvider' => $baseDir . '/lib/private/FilesMetadata/Provider/OriginalDateTimeMetadataProvider.php',
'OC\\FilesMetadata\\Service\\IndexRequestService' => $baseDir . '/lib/private/FilesMetadata/Service/IndexRequestService.php',
'OC\\FilesMetadata\\Service\\MetadataRequestService' => $baseDir . '/lib/private/FilesMetadata/Service/MetadataRequestService.php',
'OC\\Files\\AppData\\AppData' => $baseDir . '/lib/private/Files/AppData/AppData.php',
'OC\\Files\\AppData\\Factory' => $baseDir . '/lib/private/Files/AppData/Factory.php',
'OC\\Files\\Cache\\Cache' => $baseDir . '/lib/private/Files/Cache/Cache.php',
Expand Down Expand Up @@ -1458,7 +1480,6 @@
'OC\\Metadata\\IMetadataManager' => $baseDir . '/lib/private/Metadata/IMetadataManager.php',
'OC\\Metadata\\IMetadataProvider' => $baseDir . '/lib/private/Metadata/IMetadataProvider.php',
'OC\\Metadata\\MetadataManager' => $baseDir . '/lib/private/Metadata/MetadataManager.php',
'OC\\Metadata\\Provider\\ExifProvider' => $baseDir . '/lib/private/Metadata/Provider/ExifProvider.php',
'OC\\Migration\\BackgroundRepair' => $baseDir . '/lib/private/Migration/BackgroundRepair.php',
'OC\\Migration\\ConsoleOutput' => $baseDir . '/lib/private/Migration/ConsoleOutput.php',
'OC\\Migration\\SimpleOutput' => $baseDir . '/lib/private/Migration/SimpleOutput.php',
Expand Down
23 changes: 22 additions & 1 deletion lib/composer/composer/autoload_static.php
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,14 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\Federation\\ICloudId' => __DIR__ . '/../../..' . '/lib/public/Federation/ICloudId.php',
'OCP\\Federation\\ICloudIdManager' => __DIR__ . '/../../..' . '/lib/public/Federation/ICloudIdManager.php',
'OCP\\Files' => __DIR__ . '/../../..' . '/lib/public/Files.php',
'OCP\\FilesMetadata\\Event\\MetadataBackgroundEvent' => __DIR__ . '/../../..' . '/lib/public/FilesMetadata/Event/MetadataBackgroundEvent.php',
'OCP\\FilesMetadata\\Event\\MetadataLiveEvent' => __DIR__ . '/../../..' . '/lib/public/FilesMetadata/Event/MetadataLiveEvent.php',
'OCP\\FilesMetadata\\Exceptions\\FilesMetadataException' => __DIR__ . '/../../..' . '/lib/public/FilesMetadata/Exceptions/FilesMetadataException.php',
'OCP\\FilesMetadata\\Exceptions\\FilesMetadataNotFoundException' => __DIR__ . '/../../..' . '/lib/public/FilesMetadata/Exceptions/FilesMetadataNotFoundException.php',
'OCP\\FilesMetadata\\Exceptions\\FilesMetadataTypeException' => __DIR__ . '/../../..' . '/lib/public/FilesMetadata/Exceptions/FilesMetadataTypeException.php',
'OCP\\FilesMetadata\\IFilesMetadataManager' => __DIR__ . '/../../..' . '/lib/public/FilesMetadata/IFilesMetadataManager.php',
'OCP\\FilesMetadata\\Model\\IFilesMetadata' => __DIR__ . '/../../..' . '/lib/public/FilesMetadata/Model/IFilesMetadata.php',
'OCP\\FilesMetadata\\Model\\IMetadataQuery' => __DIR__ . '/../../..' . '/lib/public/FilesMetadata/Model/IMetadataQuery.php',
'OCP\\Files\\AlreadyExistsException' => __DIR__ . '/../../..' . '/lib/public/Files/AlreadyExistsException.php',
'OCP\\Files\\AppData\\IAppDataFactory' => __DIR__ . '/../../..' . '/lib/public/Files/AppData/IAppDataFactory.php',
'OCP\\Files\\Cache\\AbstractCacheEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Cache/AbstractCacheEvent.php',
Expand Down Expand Up @@ -1038,6 +1046,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OC\\Core\\Command\\Encryption\\SetDefaultModule' => __DIR__ . '/../../..' . '/core/Command/Encryption/SetDefaultModule.php',
'OC\\Core\\Command\\Encryption\\ShowKeyStorageRoot' => __DIR__ . '/../../..' . '/core/Command/Encryption/ShowKeyStorageRoot.php',
'OC\\Core\\Command\\Encryption\\Status' => __DIR__ . '/../../..' . '/core/Command/Encryption/Status.php',
'OC\\Core\\Command\\FilesMetadata\\Get' => __DIR__ . '/../../..' . '/core/Command/FilesMetadata/Get.php',
'OC\\Core\\Command\\Group\\Add' => __DIR__ . '/../../..' . '/core/Command/Group/Add.php',
'OC\\Core\\Command\\Group\\AddUser' => __DIR__ . '/../../..' . '/core/Command/Group/AddUser.php',
'OC\\Core\\Command\\Group\\Delete' => __DIR__ . '/../../..' . '/core/Command/Group/Delete.php',
Expand Down Expand Up @@ -1208,6 +1217,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OC\\Core\\Migrations\\Version28000Date20230616104802' => __DIR__ . '/../../..' . '/core/Migrations/Version28000Date20230616104802.php',
'OC\\Core\\Migrations\\Version28000Date20230728104802' => __DIR__ . '/../../..' . '/core/Migrations/Version28000Date20230728104802.php',
'OC\\Core\\Migrations\\Version28000Date20230803221055' => __DIR__ . '/../../..' . '/core/Migrations/Version28000Date20230803221055.php',
'OC\\Core\\Migrations\\Version28000Date20231004103301' => __DIR__ . '/../../..' . '/core/Migrations/Version28000Date20231004103301.php',
'OC\\Core\\Notification\\CoreNotifier' => __DIR__ . '/../../..' . '/core/Notification/CoreNotifier.php',
'OC\\Core\\Service\\LoginFlowV2Service' => __DIR__ . '/../../..' . '/core/Service/LoginFlowV2Service.php',
'OC\\DB\\Adapter' => __DIR__ . '/../../..' . '/lib/private/DB/Adapter.php',
Expand Down Expand Up @@ -1292,6 +1302,18 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OC\\Federation\\CloudFederationShare' => __DIR__ . '/../../..' . '/lib/private/Federation/CloudFederationShare.php',
'OC\\Federation\\CloudId' => __DIR__ . '/../../..' . '/lib/private/Federation/CloudId.php',
'OC\\Federation\\CloudIdManager' => __DIR__ . '/../../..' . '/lib/private/Federation/CloudIdManager.php',
'OC\\FilesMetadata\\Event\\MetadataEventBase' => __DIR__ . '/../../..' . '/lib/private/FilesMetadata/Event/MetadataEventBase.php',
'OC\\FilesMetadata\\FilesMetadataManager' => __DIR__ . '/../../..' . '/lib/private/FilesMetadata/FilesMetadataManager.php',
'OC\\FilesMetadata\\Job\\UpdateSingleMetadata' => __DIR__ . '/../../..' . '/lib/private/FilesMetadata/Job/UpdateSingleMetadata.php',
'OC\\FilesMetadata\\Listener\\MetadataDelete' => __DIR__ . '/../../..' . '/lib/private/FilesMetadata/Listener/MetadataDelete.php',
'OC\\FilesMetadata\\Listener\\MetadataUpdate' => __DIR__ . '/../../..' . '/lib/private/FilesMetadata/Listener/MetadataUpdate.php',
'OC\\FilesMetadata\\Model\\FilesMetadata' => __DIR__ . '/../../..' . '/lib/private/FilesMetadata/Model/FilesMetadata.php',
'OC\\FilesMetadata\\Model\\MetadataQuery' => __DIR__ . '/../../..' . '/lib/private/FilesMetadata/Model/MetadataQuery.php',
'OC\\FilesMetadata\\Model\\MetadataValueWrapper' => __DIR__ . '/../../..' . '/lib/private/FilesMetadata/Model/MetadataValueWrapper.php',
'OC\\FilesMetadata\\Provider\\ExifMetadataProvider' => __DIR__ . '/../../..' . '/lib/private/FilesMetadata/Provider/ExifMetadataProvider.php',
'OC\\FilesMetadata\\Provider\\OriginalDateTimeMetadataProvider' => __DIR__ . '/../../..' . '/lib/private/FilesMetadata/Provider/OriginalDateTimeMetadataProvider.php',
'OC\\FilesMetadata\\Service\\IndexRequestService' => __DIR__ . '/../../..' . '/lib/private/FilesMetadata/Service/IndexRequestService.php',
'OC\\FilesMetadata\\Service\\MetadataRequestService' => __DIR__ . '/../../..' . '/lib/private/FilesMetadata/Service/MetadataRequestService.php',
'OC\\Files\\AppData\\AppData' => __DIR__ . '/../../..' . '/lib/private/Files/AppData/AppData.php',
'OC\\Files\\AppData\\Factory' => __DIR__ . '/../../..' . '/lib/private/Files/AppData/Factory.php',
'OC\\Files\\Cache\\Cache' => __DIR__ . '/../../..' . '/lib/private/Files/Cache/Cache.php',
Expand Down Expand Up @@ -1491,7 +1513,6 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OC\\Metadata\\IMetadataManager' => __DIR__ . '/../../..' . '/lib/private/Metadata/IMetadataManager.php',
'OC\\Metadata\\IMetadataProvider' => __DIR__ . '/../../..' . '/lib/private/Metadata/IMetadataProvider.php',
'OC\\Metadata\\MetadataManager' => __DIR__ . '/../../..' . '/lib/private/Metadata/MetadataManager.php',
'OC\\Metadata\\Provider\\ExifProvider' => __DIR__ . '/../../..' . '/lib/private/Metadata/Provider/ExifProvider.php',
'OC\\Migration\\BackgroundRepair' => __DIR__ . '/../../..' . '/lib/private/Migration/BackgroundRepair.php',
'OC\\Migration\\ConsoleOutput' => __DIR__ . '/../../..' . '/lib/private/Migration/ConsoleOutput.php',
'OC\\Migration\\SimpleOutput' => __DIR__ . '/../../..' . '/lib/private/Migration/SimpleOutput.php',
Expand Down
125 changes: 125 additions & 0 deletions lib/private/FilesMetadata/Provider/ExifMetadataProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<?php

declare(strict_types=1);
/**
* @copyright Copyright 2022 Carl Schwan <[email protected]>
* @copyright Copyright 2022 Louis Chmn <[email protected]>
* @license AGPL-3.0-or-later
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* 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, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/

namespace OC\FilesMetadata\Provider;

use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use OCP\Files\File;
use OCP\FilesMetadata\Event\MetadataLiveEvent;
use Psr\Log\LoggerInterface;

// Extract EXIF, IFD0, and GPS data from a picture file.
// EXIF data reference: https://web.archive.org/web/20220428165430/exif.org/Exif2-2.PDF
class ExifMetadataProvider implements IEventListener {
public function __construct(
private LoggerInterface $logger
) {}

public function handle(Event $event): void {
if (!($event instanceof MetadataLiveEvent)) {
return;
}

$node = $event->getNode();

if (!$node instanceof File) {
return;
}

if (!preg_match('/image\/(png|jpeg|heif|webp|tiff)/', $node->getMimetype())) {
return;
}

if (!extension_loaded('exif')) {
return;
}

$fileDescriptor = $node->fopen('rb');
if ($fileDescriptor === false) {
return;
}

$rawExifData = null;

try {
// HACK: The stream_set_chunk_size call is needed to make reading exif data reliable.
// This is to trigger this condition: https://github.com/php/php-src/blob/d64aa6f646a7b5e58359dc79479860164239580a/main/streams/streams.c#L710
// But I don't understand yet why 1 as a special meaning.
$oldBufferSize = stream_set_chunk_size($fileDescriptor, 1);
$rawExifData = @exif_read_data($fileDescriptor, 'EXIF, GPS', true);
// We then revert the change after having read the exif data.
stream_set_chunk_size($fileDescriptor, $oldBufferSize);
} catch (\Exception $ex) {
$this->logger->info("Failed to extract metadata for " . $node->getId(), ['exception' => $ex]);
}

if ($rawExifData && array_key_exists('EXIF', $rawExifData)) {
$event->getMetadata()->setArray('files-exif', $rawExifData['EXIF']);
}

if ($rawExifData && array_key_exists('IFD0', $rawExifData)) {
$event->getMetadata()->setArray('files-ifd0', $rawExifData['IFD0']);
}

if (
$rawExifData &&
array_key_exists('GPS', $rawExifData) &&
array_key_exists('GPSLatitude', $rawExifData['GPS']) && array_key_exists('GPSLatitudeRef', $rawExifData['GPS']) &&
array_key_exists('GPSLongitude', $rawExifData['GPS']) && array_key_exists('GPSLongitudeRef', $rawExifData['GPS'])
) {
$event->getMetadata()->setArray('files-gps', [
'latitude' => $this->gpsDegreesToDecimal($rawExifData['GPS']['GPSLatitude'], $rawExifData['GPS']['GPSLatitudeRef']),
'longitude' => $this->gpsDegreesToDecimal($rawExifData['GPS']['GPSLongitude'], $rawExifData['GPS']['GPSLongitudeRef']),
'altitude' => ($rawExifData['GPS']['GPSAltitudeRef'] === "\u{0000}" ? 1 : -1) * $this->parseGPSData($rawExifData['GPS']['GPSAltitude']),
]);
}
}

/**
* @param array|string $coordinates
*/
private function gpsDegreesToDecimal($coordinates, ?string $hemisphere): float {
if (is_string($coordinates)) {
$coordinates = array_map("trim", explode(",", $coordinates));
}

if (count($coordinates) !== 3) {
throw new \Exception('Invalid coordinate format: ' . json_encode($coordinates));
}

[$degrees, $minutes, $seconds] = array_map(fn ($rawDegree) => $this->parseGPSData($rawDegree), $coordinates);

$sign = ($hemisphere === 'W' || $hemisphere === 'S') ? -1 : 1;
return $sign * ($degrees + $minutes / 60 + $seconds / 3600);
}

private function parseGPSData(string $rawData): float {
$parts = explode('/', $rawData);

if ($parts[1] === '0') {
return 0;
}

return floatval($parts[0]) / floatval($parts[1] ?? 1);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?php

declare(strict_types=1);
/**
* @copyright Copyright 2022 Carl Schwan <[email protected]>
* @copyright Copyright 2022 Louis Chmn <[email protected]>
* @license AGPL-3.0-or-later
*
* This code is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License, version 3,
* as published by the Free Software Foundation.
*
* 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, version 3,
* along with this program. If not, see <http://www.gnu.org/licenses/>
*
*/

namespace OC\FilesMetadata\Provider;

use DateTime;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use OCP\Files\File;
use OCP\FilesMetadata\Event\MetadataLiveEvent;

class OriginalDateTimeMetadataProvider implements IEventListener {
public function __construct() {}

public function handle(Event $event): void {
if (!($event instanceof MetadataLiveEvent)) {
return;
}

$node = $event->getNode();

if (!$node instanceof File) {
return;
}

$metadata = $event->getMetadata();

if (!$metadata->hasKey('files-exif')) {
return;
}

if (!array_key_exists('DateTimeOriginal', $metadata->getArray('files-exif'))) {
return;
}

$rawDateTimeOriginal = $metadata->getArray('files-exif')['DateTimeOriginal'];
$dateTimeOriginal = DateTime::createFromFormat("Y:m:d G:i:s", $rawDateTimeOriginal);
$metadata->setInt('files-original_date_time', $dateTimeOriginal->getTimestamp(), true);
}
}
Loading