Skip to content
This repository was archived by the owner on Oct 13, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
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
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,21 @@

All notable changes to this project will be documented in this file.

## [0.3.6 - 2023-06-19]

[`cloud_py_api`](https://github.com/cloud-py-api/cloud_py_api) is **required** to be installed
(or updated) and enabled first.

### Added

- Nextcloud Hub 5 (27) support
- Option to delete all duplicates in group except the largest one

### Updated

- Updated packages
- Updated l10n

## [0.3.5 - 2023-03-23]

[`cloud_py_api`](https://github.com/cloud-py-api/cloud_py_api) is **required** to be installed
Expand Down
11 changes: 0 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,3 @@ Starting from 0.2.0 version MediaDC is only included in Nextcloud v25 and higher
* [Andrey Borysenko](https://github.com/andrey18106)
* [Alexander Piskun](https://github.com/bigcat88)

## Support

You can support us in several ways:

- ⭐ Star our work (it really motivates)
- ❗ Create an Issue or feature request (bring to us an excellent idea)
- 💁 Resolve some Issue or create a Pull Request (contribute to this project)
- 🪙 Donate with any amount with one of the links below (fund this project)

[![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/donate?hosted_button_id=H5PLJJMWLDNJQ)
[![Liberapay](https://liberapay.com/assets/widgets/donate.svg)](https://liberapay.com/cloud_py_api/donate)
16 changes: 2 additions & 14 deletions appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,9 @@ This app allows to find duplicate or similar 📸📹 photos and videos
* **Save your time and cloud space** The title says all...

Quick start guide and further information in our [Wiki](https://github.com/cloud-py-api/mediadc/wiki).

### Support

You can support us in several ways:

- ⭐ Star our work (it really motivates)
- ❗ Create an Issue or feature request (bring to us an excellent idea)
- 💁 Resolve some Issue or create a Pull Request (contribute to this project)
- 🪙 Donate with any amount with one of the links below (fund this project)

[![PayPal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/donate?hosted_button_id=H5PLJJMWLDNJQ)
[![Liberapay](https://liberapay.com/assets/widgets/donate.svg)](https://liberapay.com/cloud_py_api/donate)
]]>
</description>
<version>0.3.5</version>
<version>0.3.6</version>
<licence>agpl</licence>
<author mail="andrey18106x@gmail.com" homepage="https://github.com/andrey18106">Andrey Borysenko</author>
<author mail="bigcat88@icloud.com" homepage="https://github.com/bigcat88">Alexander Piskun</author>
Expand All @@ -56,7 +44,7 @@ You can support us in several ways:
<screenshot>https://raw.githubusercontent.com/cloud-py-api/mediadc/main/screenshots/mediadc_filesplugin.png</screenshot>
<dependencies>
<php min-version="7.4" min-int-size="64" />
<nextcloud min-version="25" max-version="26" />
<nextcloud min-version="25" max-version="28" />
</dependencies>
<background-jobs>
<job>OCA\MediaDC\BackgroundJob\CollectorCleanupJob</job>
Expand Down
1 change: 1 addition & 0 deletions appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@

// BATCH ACTIONS API
['name' => 'collector#removeTaskDetailGroups', 'url' => '/api/v1/tasks/{taskId}/details/remove', 'verb' => 'POST'],
['name' => 'collector#deleteTaskDetailGroupsFiles', 'url' => '/api/v1/tasks/{taskId}/details/delete', 'verb' => 'POST'],
['name' => 'collector#removeTaskDetailFiles', 'url' => '/api/v1/tasks/{taskId}/files/{groupId}/remove', 'verb' => 'POST'],
['name' => 'collector#deleteTaskDetailFiles', 'url' => '/api/v1/tasks/{taskId}/files/{groupId}/delete', 'verb' => 'POST'],
]
Expand Down
2 changes: 1 addition & 1 deletion css/style.css
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* @copyright Copyright (c) 2022 Andrey Borysenko <andrey18106x@gmail.com>
*
* @copyright opyright (c) 2022 Alexander Piskun <bigcat88@icloud.com>
* @copyright Copyright (c) 2022 Alexander Piskun <bigcat88@icloud.com>
*
* @author 2022 Andrey Borysenko <andrey18106x@gmail.com>
*
Expand Down
19 changes: 17 additions & 2 deletions lib/Controller/CollectorController.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@

namespace OCA\MediaDC\Controller;

use Exception;
use OCP\IRequest;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
Expand Down Expand Up @@ -201,15 +202,17 @@ public function getTaskInfo(int $taskId): JSONResponse {
* @param int $taskId target task id
* @param string $format export file format (xml, json)
*
* @return DataDownloadResponse
* @throws Exception
* @return DataDownloadResponse|null
*/
public function getTaskResultsExport(int $taskId, string $format): DataDownloadResponse {
public function getTaskResultsExport(int $taskId, string $format): ?DataDownloadResponse {
if (in_array($format, ['xml', 'json'])) {
$export = $this->service->exportTaskResults(intval($taskId), $format);
if ($export) {
return new DataDownloadResponse($export['data'], $export['filename'], $export['contentType']);
}
}
throw new Exception('Bad request. Requested export format is not supported.');
}

/**
Expand Down Expand Up @@ -330,6 +333,18 @@ public function removeTaskDetailGroups(int $taskId, array $groupIds): JSONRespon
}
}

/**
* @NoAdminRequired
* @NoCSRFRequired
*/
public function deleteTaskDetailGroupsFiles(int $taskId, array $groupIds): JSONResponse {
if ($taskId && $groupIds) {
return new JSONResponse($this->service->deleteTaskDetailGroupsFiles($taskId, $groupIds), Http::STATUS_OK);
} else {
return new JSONResponse(['success' => false], Http::STATUS_OK);
}
}

/**
* @NoAdminRequired
* @NoCSRFRequired
Expand Down
16 changes: 16 additions & 0 deletions lib/Db/CollectorTaskDetailMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,22 @@ public function findAllByGroupId(int $taskId, int $groupId): array {
}, $qb->executeQuery()->fetchAll());
}

public function findAllByGroupIdSize(int $taskId, int $groupId): array {
$qb = $this->db->getQueryBuilder();
$qb->select(
'mdc_t_d.fileid',
)
->from($this->tableName, 'mdc_t_d')
->innerJoin('mdc_t_d', 'filecache', 'f', $qb->expr()->eq('mdc_t_d.fileid', 'f.fileid'))
->where($qb->expr()->eq('mdc_t_d.task_id', $qb->createNamedParameter($taskId, IQueryBuilder::PARAM_INT)))
->andWhere($qb->expr()->eq('mdc_t_d.group_id', $qb->createNamedParameter($groupId, IQueryBuilder::PARAM_INT)))
->orderBy('mdc_t_d.group_id', 'ASC')
->addOrderBy('f.size', 'DESC');
return array_map(function ($row) {
return intval($row['fileid']);
}, $qb->executeQuery()->fetchAll());
}

/**
* @param int $taskId
* @param int $limit
Expand Down
53 changes: 46 additions & 7 deletions lib/Service/CollectorService.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
namespace OCA\MediaDC\Service;

use DOMDocument;
use OCA\Files_Sharing\SharedStorage;
use OCP\Files\File;
use OCP\Files\Node;
use OCP\Files\Folder;
Expand Down Expand Up @@ -768,7 +769,7 @@ public function deleteTaskDetailFile($taskId, $groupId, $fileid, $removeIfOneLef
} catch (NotPermittedException | NotFoundException $e) {
return [
'success' => false,
'not_permited' => $e instanceof NotPermittedException,
'not_permitted' => $e instanceof NotPermittedException,
'not_found' => $e instanceof NotFoundException,
];
}
Expand All @@ -780,7 +781,7 @@ public function deleteTaskDetailFile($taskId, $groupId, $fileid, $removeIfOneLef
}

/**
* Remove ColectorTaskDetail groups with deleting coresponding files
* Remove CollectorTaskDetail groups with deleting corresponding files
*
* @param int $taskId
* @param array $groupIds
Expand All @@ -801,7 +802,45 @@ public function removeTaskDetailGroups(int $taskId, array $groupIds) {
}

/**
* Delete ColectorTaskDetail groups with deleting coresponding files
* Delete all CollectorTaskDetail group files except one largest
*
* @param int $taskId
* @param array $groupIds
*
* @return array
*/
public function deleteTaskDetailGroupsFiles(int $taskId, array $groupIds) {
$result = [];
foreach ($groupIds as $groupId) {
$groupFiles = $this->tasksDetailsMapper->findAllByGroupIdSize($taskId, $groupId);
$largestFileId = array_splice($groupFiles, 0, 1)[0];
$this->tasksDetailsMapper->deleteGroupFiles($taskId, $groupId, [$largestFileId]);
$this->markResolvedPhoto($largestFileId, true);
$this->markResolvedVideo($largestFileId, true);
$collectorTask = null;
foreach ($groupFiles as $fileId) {
$deleteFileResult = $this->deleteTaskDetailFile($taskId, $groupId, $fileId, false);
if ($deleteFileResult['success']) {
$collectorTask = $deleteFileResult['task'];
$fileIdIndex = array_search($fileId, $groupFiles);
if ($fileIdIndex !== false) {
array_splice($groupFiles, $fileIdIndex, 1)[0];
}
}
}
if (count($groupFiles) === 0) {
$result[] = intval($groupId);
}
}
return [
'success' => count($result) === count($groupIds),
'removedGroupIds' => $result,
'task' => $collectorTask,
];
}

/**
* Delete CollectorTaskDetail groups with deleting corresponding files
*
* @param int $taskId
* @param int $groupId
Expand All @@ -813,7 +852,7 @@ public function deleteTaskDetailFiles(int $taskId, int $groupId, array $fileIds)
$result = [];
$errors = [
'locked' => [],
'not_permited' => [],
'not_permitted' => [],
'not_found' => [],
];
$groupFiles = $this->tasksDetailsMapper->findAllByGroupId($taskId, $groupId);
Expand All @@ -828,8 +867,8 @@ public function deleteTaskDetailFiles(int $taskId, int $groupId, array $fileIds)
if (isset($deleteFileResult['locked']) && $deleteFileResult['locked']) {
array_push($errors['locked'], $fileId);
}
if (isset($deleteFileResult['not_permited']) && $deleteFileResult['not_permited']) {
array_push($errors['not_permited'], $fileId);
if (isset($deleteFileResult['not_permitted']) && $deleteFileResult['not_permitted']) {
array_push($errors['not_permitted'], $fileId);
}
if (isset($deleteFileResult['not_found']) && $deleteFileResult['not_found']) {
array_push($errors['not_found'], $fileId);
Expand All @@ -855,7 +894,7 @@ public function deleteTaskDetailFiles(int $taskId, int $groupId, array $fileIds)
}

/**
* Remove ColectorTaskDetail groups with deleting coresponding files
* Remove CollectorTaskDetail groups with deleting corresponding files
*
* @param int $taskId
* @param int $groupId
Expand Down
18 changes: 17 additions & 1 deletion lib/Settings/AdminSettings.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,33 @@
namespace OCA\MediaDC\Settings;

use OCA\MediaDC\AppInfo\Application;
use OCA\MediaDC\Db\SettingMapper;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Services\IInitialState;
use OCP\Settings\ISettings;

class AdminSettings implements ISettings {
public function __construct() {
/** @var SettingMapper */
private $settingMapper;

/** @var IInitialState */
private $initialState;

public function __construct(
IInitialState $initialState,
SettingMapper $settingMapper
) {
$this->settingMapper = $settingMapper;
$this->initialState = $initialState;
}

/**
* @return TemplateResponse
*/
public function getForm() {
$settings = $this->settingMapper->findAll();
$this->initialState->provideInitialState('settings', $settings);

return new TemplateResponse(Application::APP_ID, 'admin');
}

Expand Down
Loading