Generate.php 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * @copyright Copyright (c) 2023 Robin Appelman <robin@icewind.nl>
  5. *
  6. * @license GNU AGPL version 3 or any later version
  7. *
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU Affero General Public License as
  10. * published by the Free Software Foundation, either version 3 of the
  11. * License, or (at your option) any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU Affero General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU Affero General Public License
  19. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. *
  21. */
  22. namespace OC\Core\Command\Preview;
  23. use OCP\Files\Config\IUserMountCache;
  24. use OCP\Files\File;
  25. use OCP\Files\IRootFolder;
  26. use OCP\Files\Node;
  27. use OCP\Files\NotFoundException;
  28. use OCP\IPreview;
  29. use Symfony\Component\Console\Command\Command;
  30. use Symfony\Component\Console\Input\InputArgument;
  31. use Symfony\Component\Console\Input\InputInterface;
  32. use Symfony\Component\Console\Input\InputOption;
  33. use Symfony\Component\Console\Output\OutputInterface;
  34. class Generate extends Command {
  35. public function __construct(
  36. private IRootFolder $rootFolder,
  37. private IUserMountCache $userMountCache,
  38. private IPreview $previewManager,
  39. ) {
  40. parent::__construct();
  41. }
  42. protected function configure() {
  43. $this
  44. ->setName('preview:generate')
  45. ->setDescription('generate a preview for a file')
  46. ->addArgument("file", InputArgument::REQUIRED, "path or fileid of the file to generate the preview for")
  47. ->addOption("size", "s", InputOption::VALUE_IS_ARRAY | InputOption::VALUE_REQUIRED, "size to generate the preview for in pixels, defaults to 64x64", ["64x64"])
  48. ->addOption("crop", "c", InputOption::VALUE_NONE, "crop the previews instead of maintaining aspect ratio")
  49. ->addOption("mode", "m", InputOption::VALUE_REQUIRED, "mode for generating uncropped previews, 'cover' or 'fill'", IPreview::MODE_FILL);
  50. }
  51. protected function execute(InputInterface $input, OutputInterface $output): int {
  52. $fileInput = $input->getArgument("file");
  53. $sizes = $input->getOption("size");
  54. $sizes = array_map(function (string $size) use ($output, &$error) {
  55. if (str_contains($size, 'x')) {
  56. $sizeParts = explode('x', $size, 2);
  57. } else {
  58. $sizeParts = [$size, $size];
  59. }
  60. if (!is_numeric($sizeParts[0]) || !is_numeric($sizeParts[1])) {
  61. $output->writeln("<error>Invalid size $size</error>");
  62. return null;
  63. }
  64. return array_map("intval", $sizeParts);
  65. }, $sizes);
  66. if (in_array(null, $sizes)) {
  67. return 1;
  68. }
  69. $mode = $input->getOption("mode");
  70. if ($mode !== IPreview::MODE_FILL && $mode !== IPreview::MODE_COVER) {
  71. $output->writeln("<error>Invalid mode $mode</error>");
  72. return 1;
  73. }
  74. $crop = $input->getOption("crop");
  75. $file = $this->getFile($fileInput);
  76. if (!$file) {
  77. $output->writeln("<error>File $fileInput not found</error>");
  78. return 1;
  79. }
  80. if (!$file instanceof File) {
  81. $output->writeln("<error>Can't generate previews for folders</error>");
  82. return 1;
  83. }
  84. if (!$this->previewManager->isAvailable($file)) {
  85. $output->writeln("<error>No preview generator available for file of type" . $file->getMimetype() . "</error>");
  86. return 1;
  87. }
  88. $specifications = array_map(function (array $sizes) use ($crop, $mode) {
  89. return [
  90. 'width' => $sizes[0],
  91. 'height' => $sizes[1],
  92. 'crop' => $crop,
  93. 'mode' => $mode,
  94. ];
  95. }, $sizes);
  96. $this->previewManager->generatePreviews($file, $specifications);
  97. if (count($specifications) > 1) {
  98. $output->writeln("generated <info>" . count($specifications) . "</info> previews");
  99. } else {
  100. $output->writeln("preview generated");
  101. }
  102. return 0;
  103. }
  104. private function getFile(string $fileInput): ?Node {
  105. if (is_numeric($fileInput)) {
  106. $mounts = $this->userMountCache->getMountsForFileId((int)$fileInput);
  107. if (!$mounts) {
  108. return null;
  109. }
  110. $mount = $mounts[0];
  111. $userFolder = $this->rootFolder->getUserFolder($mount->getUser()->getUID());
  112. $nodes = $userFolder->getById((int)$fileInput);
  113. if (!$nodes) {
  114. return null;
  115. }
  116. return $nodes[0];
  117. } else {
  118. try {
  119. return $this->rootFolder->get($fileInput);
  120. } catch (NotFoundException $e) {
  121. return null;
  122. }
  123. }
  124. }
  125. }