Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP: timeline server supporting features #466

Closed
wants to merge 4 commits into from
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
command working, prepred to add wrapper
Signed-off-by: xiangbin.li <[email protected]>
dassio committed Oct 6, 2020
commit ff4930d5b26111176648f31148faf2e5e78aefd7
52 changes: 28 additions & 24 deletions appinfo/info.xml
Original file line number Diff line number Diff line change
@@ -1,28 +1,32 @@
<?xml version="1.0"?>
<info xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd">
<id>photos</id>
<name>Photos</name>
<summary>Your memories under your control</summary>
<description>Your memories under your control</description>
<version>1.3.0</version>
<licence>agpl</licence>
<author mail="[email protected]">John Molakvoæ</author>
<namespace>Photos</namespace>
<category>multimedia</category>
xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd">
<id>photos</id>
<name>Photos</name>
<summary>Your memories under your control</summary>
<description>Your memories under your control</description>
<version>1.3.0</version>
<licence>agpl</licence>
<author mail="[email protected]">John Molakvoæ</author>
<namespace>Photos</namespace>
<category>multimedia</category>

<website>https://github.com/nextcloud/photos</website>
<bugs>https://github.com/nextcloud/photos/issues</bugs>
<repository>https://github.com/nextcloud/photos.git</repository>
<default_enable />
<dependencies>
<nextcloud min-version="20" max-version="21" />
</dependencies>
<navigations>
<navigation>
<name>Photos</name>
<route>photos.page.index</route>
<order>1</order>
</navigation>
</navigations>
<commands>
<command>OCA\Photos\Command\ExtractMetadata</command>
</commands>

<website>https://github.com/nextcloud/photos</website>
<bugs>https://github.com/nextcloud/photos/issues</bugs>
<repository>https://github.com/nextcloud/photos.git</repository>
<default_enable />
<dependencies>
<nextcloud min-version="21" max-version="21" />
</dependencies>
<navigations>
<navigation>
<name>Photos</name>
<route>photos.page.index</route>
<order>1</order>
</navigation>
</navigations>
</info>
25 changes: 25 additions & 0 deletions appinfo/routes.php
Original file line number Diff line number Diff line change
@@ -73,5 +73,30 @@
'path' => '',
],
],
[
'name' => 'albums#getNumberByMonth',
'url' => '/api/v1/numberbymonth/{path}',
'verb' => 'GET',
'requirements' => [
'path' => '.*',
],
'defaults' => [
'path' => '',
],
],
[
'name' => 'albums#getPhotosOfMonth',
'url' => '/api/v1/photosofmonth/{path}',
'verb' => 'GET',
'requirements' => [
'yearandmonth' => '.*',
'path' => '.*',
],
'defaults' => [
'yearandmonth' => '',
'path' => '',
],
],

]
];
2 changes: 2 additions & 0 deletions lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
@@ -52,11 +52,13 @@ class Application extends App implements IBootstrap {

public function __construct() {
parent::__construct(self::APP_ID);

}

public function register(IRegistrationContext $context): void {
}

public function boot(IBootContext $context): void {
\OCP\Util::connectHook('OC_Filesystem', 'preSetup', 'OCA\Photos\Storage', 'setupStorage');
}
}
168 changes: 168 additions & 0 deletions lib/Command/ExtractMetadata.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
<?php
declare(strict_types=1);


namespace OCA\Photos\Command;

use OCP\Encryption\IManager;
use OCP\Files\File;
use OCP\Files\Folder;
use OCP\Files\IRootFolder;
use OCP\Files\NotFoundException;
use OCP\IConfig;
use OCP\IUser;
use OCP\IUserManager;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

use OCA\Photos\Db\PhotoMetadata;
use OCA\Photos\Db\PhotoMetadataMapper;
use OCA\Photos\Service\MetadataService;

class ExtractMetadata extends Command {

/** @var IUserManager */
protected $userManager;

/** @var IRootFolder */
protected $rootFolder;

/** @var IConfig */
protected $config;

/** @var OutputInterface */
protected $output;

/** @var IManager */
protected $encryptionManager;

/** @var PhotoMetadataMapper */
private $photoMetadataMapper;

/** @var MetadataService */
private $metadataService;

public function __construct(IRootFolder $rootFolder,
IUserManager $userManager,
IConfig $config,
IManager $encryptionManager,
PhotoMetadataMapper $photoMetadataMapper,
MetadataService $metadataService) {
parent::__construct();

$this->userManager = $userManager;
$this->rootFolder = $rootFolder;
$this->config = $config;
$this->encryptionManager = $encryptionManager;
$this->photoMetadataMapper = $photoMetadataMapper;
$this->metadataService = $metadataService;
}

protected function configure() {
$this
->setName('photos:extractmetadata')
->setDescription('extract metadata from image files: date taken, location...')
->addArgument(
'user_id',
InputArgument::OPTIONAL,
'extract photo metadata for the given user'
)->addOption(
'path',
'p',
InputOption::VALUE_OPTIONAL,
'limit extraction to this photo folder(album), eg. --path="/alice/files/Photos/2020-3/", the user_id is determined by the path and the user_id parameter is ignored'
);
}

protected function execute(InputInterface $input, OutputInterface $output): int {
if ($this->encryptionManager->isEnabled()) {
$output->writeln('Encryption is enabled. Aborted.');
return 1;
}

$this->output = $output;

$inputPath = $input->getOption('path');
if ($inputPath) {
$inputPath = '/' . trim($inputPath, '/');
list (, $userId,) = explode('/', $inputPath, 3);
$user = $this->userManager->get($userId);
if ($user !== null) {
$this->extractPathPhotosMetadata($user, $inputPath);
}
} else {
$userId = $input->getArgument('user_id');
if ($userId === null) {
$this->userManager->callForSeenUsers(function (IUser $user) {
$this->extractUserPhotosMetadata($user);
});
} else {
$user = $this->userManager->get($userId);
if ($user !== null) {
$this->extractUserPhotosMetadata($user);
}
}
}

return 0;
}

private function extractPathPhotosMetadata(IUser $user, string $path) {
\OC_Util::tearDownFS();
\OC_Util::setupFS($user->getUID());
$userFolder = $this->rootFolder->getUserFolder($user->getUID());
try {
$relativePath = $userFolder->getRelativePath($path);
} catch (NotFoundException $e) {
$this->output->writeln('Path not found');
return;
}
$pathFolder = $userFolder->get($relativePath);
$this->parseFolder($pathFolder);
}

private function extractUserPhotosMetadata(IUser $user) {
\OC_Util::tearDownFS();
\OC_Util::setupFS($user->getUID());

$userFolder = $this->rootFolder->getUserFolder($user->getUID());
$this->parseFolder($userFolder);

}

private function parseFolder(Folder $folder) {
// Respect the '.nomedia' file. If present don't traverse the folder
if ($folder->nodeExists('.nomedia')) {
$this->output->writeln('Skipping folder ' . $folder->getPath());
return;
}

$this->output->writeln('Scanning folder ' . $folder->getPath());

$nodes = $folder->getDirectoryListing();

foreach ($nodes as $node) {
if ($node instanceof Folder) {
$this->parseFolder($node);
} else if ($node instanceof File) {
$this->parseFile($node);
}
}
}

private function parseFile(File $file) {
if ($this->output->getVerbosity() > OutputInterface::VERBOSITY_VERBOSE) {
$this->output->writeln('Extracting metadata from ' . $file->getPath());
}
$mimeType = \OC::$server->getMimeTypeDetector()->detectPath($file->getPath());
if (in_array($mimeType, ['image/jpeg'])) {
$photoMetadata = $this->metadataService->extractPhotoMetadata($file);
$this->photoMetadataMapper->insert($photoMetadata);
}
}

}

Loading