Lot of de-duplication

pull/221/head
Varun Patil 2022-11-09 22:19:44 -08:00
parent 67e5c835ce
commit 11afad852b
7 changed files with 86 additions and 165 deletions

View File

@ -53,8 +53,7 @@ return [
['name' => 'Faces#preview', 'url' => '/api/faces/preview/{id}', 'verb' => 'GET'],
['name' => 'Image#info', 'url' => '/api/image/info/{id}', 'verb' => 'GET'],
['name' => 'Image#edit', 'url' => '/api/image/edit/{id}', 'verb' => 'PATCH'],
['name' => 'Image#setExif', 'url' => '/api/image/set-exif/{id}', 'verb' => 'PUT'],
['name' => 'Image#setExif', 'url' => '/api/image/set-exif/{id}', 'verb' => 'PATCH'],
['name' => 'Archive#archive', 'url' => '/api/archive/{id}', 'verb' => 'PATCH'],

View File

@ -31,6 +31,7 @@ use OCP\App\IAppManager;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\JSONResponse;
use OCP\Files\File;
use OCP\Files\Folder;
use OCP\Files\IRootFolder;
use OCP\IConfig;
@ -133,6 +134,23 @@ class ApiBase extends Controller
return $folder;
}
protected function getUserFile(int $id): File
{
$user = $this->userSession->getUser();
if (null === $user) {
return null;
}
$userFolder = $this->rootFolder->getUserFolder($user->getUID());
// Check for permissions and get numeric Id
$file = $userFolder->getById($id);
if (0 === \count($file)) {
return null;
}
return $file[0];
}
protected function isRecursive()
{
return null === $this->request->getParam('folder');

View File

@ -38,18 +38,10 @@ class ImageController extends ApiBase
*/
public function info(string $id): JSONResponse
{
$user = $this->userSession->getUser();
if (null === $user) {
return new JSONResponse([], Http::STATUS_PRECONDITION_FAILED);
}
$userFolder = $this->rootFolder->getUserFolder($user->getUID());
// Check for permissions and get numeric Id
$file = $userFolder->getById((int) $id);
if (0 === \count($file)) {
$file = $this->getUserFile((int) $id);
if (!$file) {
return new JSONResponse([], Http::STATUS_NOT_FOUND);
}
$file = $file[0];
// Get the image info
$basic = false !== $this->request->getParam('basic', false);
@ -57,85 +49,21 @@ class ImageController extends ApiBase
// Get latest exif data if requested
if ($this->request->getParam('current', false)) {
$info["current"] = Exif::getExifFromFile($file);
$info['current'] = Exif::getExifFromFile($file);
}
return new JSONResponse($info, Http::STATUS_OK);
}
/**
* @NoAdminRequired
*
* Change exif data for one file
*
* @param string fileid
*/
public function edit(string $id): JSONResponse
{
$user = $this->userSession->getUser();
if (null === $user) {
return new JSONResponse([], Http::STATUS_PRECONDITION_FAILED);
}
$userFolder = $this->rootFolder->getUserFolder($user->getUID());
// Check for permissions and get numeric Id
$file = $userFolder->getById((int) $id);
if (0 === \count($file)) {
return new JSONResponse([], Http::STATUS_NOT_FOUND);
}
$file = $file[0];
// Check if user has permissions
if (!$file->isUpdateable()) {
return new JSONResponse([], Http::STATUS_FORBIDDEN);
}
// Get new date from body
$body = $this->request->getParams();
if (!isset($body['date'])) {
return new JSONResponse(['message' => 'Missing date'], Http::STATUS_BAD_REQUEST);
}
// Make sure the date is valid
try {
Exif::parseExifDate($body['date']);
} catch (\Exception $e) {
return new JSONResponse(['message' => $e->getMessage()], Http::STATUS_BAD_REQUEST);
}
// Update date
try {
$res = Exif::updateExifDate($file, $body['date']);
if (false === $res) {
return new JSONResponse([], Http::STATUS_INTERNAL_SERVER_ERROR);
}
} catch (\Exception $e) {
return new JSONResponse(['message' => $e->getMessage()], Http::STATUS_INTERNAL_SERVER_ERROR);
}
// Reprocess the file
$this->timelineWrite->processFile($file, true);
return $this->info($id);
}
/**
* Set the exif data for a file
* Set the exif data for a file.
*/
public function setExif(string $id): JSONResponse
{
$user = $this->userSession->getUser();
if (null === $user) {
return new JSONResponse([], Http::STATUS_PRECONDITION_FAILED);
}
$userFolder = $this->rootFolder->getUserFolder($user->getUID());
// Check for permissions and get numeric Id
$file = $userFolder->getById((int) $id);
if (0 === \count($file)) {
$file = $this->getUserFile((int) $id);
if (!$file) {
return new JSONResponse([], Http::STATUS_NOT_FOUND);
}
$file = $file[0];
// Check if user has permissions
if (!$file->isUpdateable()) {
@ -145,15 +73,45 @@ class ImageController extends ApiBase
// Get original file from body
$exif = $this->request->getParam('raw');
$path = $file->getStorage()->getLocalFile($file->getInternalPath());
try {
Exif::setExif($path, $exif);
} catch (\Exception $e) {
return new JSONResponse(['message' => $e->getMessage()], Http::STATUS_INTERNAL_SERVER_ERROR);
}
// Update remote file if not local
if (!$file->getStorage()->isLocal()) {
$file->putContent(fopen($path, 'r')); // closes the handler
}
// Reprocess the file
$this->timelineWrite->processFile($file, true);
return new JSONResponse([], Http::STATUS_OK);
}
/**
* Get a full resolution PNG for editing from a file.
*/
public function getPNG(string $id)
{
$file = $this->getUserFile((int) $id);
if (!$file) {
return new JSONResponse([], Http::STATUS_NOT_FOUND);
}
// Get the image info
$info = $this->timelineQuery->getInfoById($file->getId(), true);
// Get the image
$path = $file->getStorage()->getLocalFile($file->getInternalPath());
$image = Exif::getPNG($path, $info['exif']);
// Return the image
$response = new Http\DataDisplayResponse($image, Http::STATUS_OK, ['Content-Type' => 'image/png']);
$response->cacheFor(0);
return $response;
}
}

View File

@ -203,8 +203,7 @@ trait TimelineQueryDays
$row['w'] = (int) $row['w'];
$row['h'] = (int) $row['h'];
if (!$row['isvideo']) {
unset($row['isvideo']);
unset($row['video_duration']);
unset($row['isvideo'], $row['video_duration']);
}
if ($row['categoryid']) {
$row['isfavorite'] = 1;

View File

@ -230,29 +230,35 @@ class Exif
}
/**
* Update exif date using exiftool.
* Set exif data using raw json.
*
* @param string $newDate formatted in standard Exif format (YYYY:MM:DD HH:MM:SS)
* @param string $path to local file
* @param array $data exif data
*
* @throws \Exception on failure
*/
public static function updateExifDate(File &$file, string $newDate)
public static function setExif(string &$path, array &$data)
{
// Don't want to mess these up, definitely
if ($file->isEncrypted()) {
throw new \Exception('Cannot update exif date on encrypted files');
}
$data['SourceFile'] = $path;
$raw = json_encode([$data]);
$cmd = array_merge(self::getExiftool(), ['-json=-', $path]);
$proc = proc_open($cmd, [
0 => ['pipe', 'r'],
1 => ['pipe', 'w'],
2 => ['pipe', 'w'],
], $pipes);
// Get path to local (copy) of the file
$path = $file->getStorage()->getLocalFile($file->getInternalPath());
if (!\is_string($path)) {
throw new \Exception('Failed to get local file path');
}
fwrite($pipes[0], $raw);
fclose($pipes[0]);
// Update exif data
self::updateExifDateForLocalFile($path, $newDate);
$stdout = self::readOrTimeout($pipes[1], 30000);
fclose($pipes[1]);
fclose($pipes[2]);
proc_terminate($proc);
if (false !== strpos($stdout, 'error')) {
error_log("Exiftool error: {$stdout}");
// Update remote file if not local
if (!$file->getStorage()->isLocal()) {
$file->putContent(fopen($path, 'r')); // closes the handler
throw new \Exception('Could not set exif data: '.$stdout);
}
}
@ -415,62 +421,4 @@ class Exif
return $json[0];
}
/**
* Update exif date using exiftool for a local file.
*
* @param string $newDate formatted in standard Exif format (YYYY:MM:DD HH:MM:SS)
*
* @throws \Exception on failure
*/
private static function updateExifDateForLocalFile(string $path, string $newDate)
{
$cmd = array_merge(self::getExiftool(), ['-api', 'QuickTimeUTC=1', '-overwrite_original', '-DateTimeOriginal='.$newDate, $path]);
$proc = proc_open($cmd, [
1 => ['pipe', 'w'],
2 => ['pipe', 'w'],
], $pipes);
$stdout = self::readOrTimeout($pipes[1], 300000);
fclose($pipes[1]);
fclose($pipes[2]);
proc_terminate($proc);
if (false !== strpos($stdout, 'error')) {
error_log("Exiftool error: {$stdout}");
throw new \Exception('Could not update exif date: '.$stdout);
}
}
/**
* Set exif data using raw json.
*
* @param string $path to local file
* @param array $data exif data
*
* @throws \Exception on failure
*/
public static function setExif(string &$path, array &$data)
{
$data['SourceFile'] = $path;
$raw = json_encode([$data]);
$cmd = array_merge(self::getExiftool(), ['-json=-', $path]);
$proc = proc_open($cmd, [
0 => ['pipe', 'r'],
1 => ['pipe', 'w'],
2 => ['pipe', 'w'],
], $pipes);
fwrite($pipes[0], $raw);
fclose($pipes[0]);
$stdout = self::readOrTimeout($pipes[1], 30000);
fclose($pipes[1]);
fclose($pipes[2]);
proc_terminate($proc);
if (false !== strpos($stdout, 'error')) {
error_log("Exiftool error: {$stdout}");
throw new \Exception('Could not set exif data: '.$stdout);
}
}
}

View File

@ -215,7 +215,7 @@ export default class ImageEditor extends Mixins(GlobalMixin) {
delete exif.ExifImageSize;
// Update exif data
await axios.put(
await axios.patch(
generateUrl("/apps/memories/api/image/set-exif/{id}", {
id: fileid,
}),

View File

@ -144,7 +144,7 @@ import * as utils from "../../services/Utils";
import * as dav from "../../services/DavRequests";
const INFO_API_URL = "/apps/memories/api/image/info/{id}";
const EDIT_API_URL = "/apps/memories/api/image/edit/{id}";
const EDIT_API_URL = "/apps/memories/api/image/set-exif/{id}";
@Component({
components: {
@ -269,12 +269,11 @@ export default class EditDate extends Mixins(GlobalMixin) {
try {
this.processing = true;
const fileid = this.photos[0].fileid;
const res = await axios.patch<any>(
generateUrl(EDIT_API_URL, { id: fileid }),
{
date: this.getExifFormat(this.getDate()),
}
);
await axios.patch<any>(generateUrl(EDIT_API_URL, { id: fileid }), {
raw: {
DateTimeOriginal: this.getExifFormat(this.getDate()),
},
});
emit("files:file:updated", { fileid });
this.emitRefresh(true);
this.close();