Completed
Push — master ( 86b69c...c0595e )
by
unknown
30:51 queued 14s
created
lib/private/Preview/Movie.php 2 patches
Indentation   +169 added lines, -169 removed lines patch added patch discarded remove patch
@@ -17,173 +17,173 @@
 block discarded – undo
17 17
 use Psr\Log\LoggerInterface;
18 18
 
19 19
 class Movie extends ProviderV2 {
20
-	private IConfig $config;
21
-
22
-	private ?string $binary = null;
23
-
24
-	public function __construct(array $options = []) {
25
-		parent::__construct($options);
26
-		$this->config = Server::get(IConfig::class);
27
-	}
28
-
29
-	public function getMimeType(): string {
30
-		return '/video\/.*/';
31
-	}
32
-
33
-	/**
34
-	 * {@inheritDoc}
35
-	 */
36
-	public function isAvailable(FileInfo $file): bool {
37
-		if (is_null($this->binary)) {
38
-			if (isset($this->options['movieBinary'])) {
39
-				$this->binary = $this->options['movieBinary'];
40
-			}
41
-		}
42
-		return is_string($this->binary);
43
-	}
44
-
45
-	/**
46
-	 * {@inheritDoc}
47
-	 */
48
-	public function getThumbnail(File $file, int $maxX, int $maxY): ?IImage {
49
-		// TODO: use proc_open() and stream the source file ?
50
-
51
-		if (!$this->isAvailable($file)) {
52
-			return null;
53
-		}
54
-
55
-		$result = null;
56
-		if ($this->useTempFile($file)) {
57
-			// Try downloading 5 MB first, as it's likely that the first frames are present there.
58
-			// In some cases this doesn't work, for example when the moov atom is at the
59
-			// end of the file, so if it fails we fall back to getting the full file.
60
-			// Unless the file is not local (e.g. S3) as we do not want to download the whole (e.g. 37Gb) file
61
-			if ($file->getStorage()->isLocal()) {
62
-				$sizeAttempts = [5242880, null];
63
-			} else {
64
-				$sizeAttempts = [5242880];
65
-			}
66
-		} else {
67
-			// size is irrelevant, only attempt once
68
-			$sizeAttempts = [null];
69
-		}
70
-
71
-		foreach ($sizeAttempts as $size) {
72
-			$absPath = $this->getLocalFile($file, $size);
73
-			if ($absPath === false) {
74
-				Server::get(LoggerInterface::class)->error(
75
-					'Failed to get local file to generate thumbnail for: ' . $file->getPath(),
76
-					['app' => 'core']
77
-				);
78
-				return null;
79
-			}
80
-
81
-			$result = $this->generateThumbNail($maxX, $maxY, $absPath, 5);
82
-			if ($result === null) {
83
-				$result = $this->generateThumbNail($maxX, $maxY, $absPath, 1);
84
-				if ($result === null) {
85
-					$result = $this->generateThumbNail($maxX, $maxY, $absPath, 0);
86
-				}
87
-			}
88
-
89
-			$this->cleanTmpFiles();
90
-
91
-			if ($result !== null) {
92
-				break;
93
-			}
94
-		}
95
-
96
-		return $result;
97
-	}
98
-
99
-	private function useHdr(string $absPath): bool {
100
-		// load ffprobe path from configuration, otherwise generate binary path using ffmpeg binary path
101
-		$ffprobe_binary = $this->config->getSystemValue('preview_ffprobe_path', null) ?? (pathinfo($this->binary, PATHINFO_DIRNAME) . '/ffprobe');
102
-		// run ffprobe on the video file to get value of "color_transfer"
103
-		$test_hdr_cmd = [$ffprobe_binary,'-select_streams', 'v:0',
104
-			'-show_entries', 'stream=color_transfer',
105
-			'-of', 'default=noprint_wrappers=1:nokey=1',
106
-			$absPath];
107
-		$test_hdr_proc = proc_open($test_hdr_cmd, [1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $test_hdr_pipes);
108
-		if ($test_hdr_proc === false) {
109
-			return false;
110
-		}
111
-		$test_hdr_stdout = trim(stream_get_contents($test_hdr_pipes[1]));
112
-		$test_hdr_stderr = trim(stream_get_contents($test_hdr_pipes[2]));
113
-		proc_close($test_hdr_proc);
114
-		// search build options for libzimg (provides zscale filter)
115
-		$ffmpeg_libzimg_installed = strpos($test_hdr_stderr, '--enable-libzimg');
116
-		// Only values of "smpte2084" and "arib-std-b67" indicate an HDR video.
117
-		// Only return true if video is detected as HDR and libzimg is installed.
118
-		if (($test_hdr_stdout === 'smpte2084' || $test_hdr_stdout === 'arib-std-b67') && $ffmpeg_libzimg_installed !== false) {
119
-			return true;
120
-		} else {
121
-			return false;
122
-		}
123
-	}
124
-
125
-	private function generateThumbNail(int $maxX, int $maxY, string $absPath, int $second): ?IImage {
126
-		$tmpPath = Server::get(ITempManager::class)->getTemporaryFile();
127
-
128
-		if ($tmpPath === false) {
129
-			Server::get(LoggerInterface::class)->error(
130
-				'Failed to get local file to generate thumbnail for: ' . $absPath,
131
-				['app' => 'core']
132
-			);
133
-			return null;
134
-		}
135
-
136
-		$binaryType = substr(strrchr($this->binary, '/'), 1);
137
-
138
-		if ($binaryType === 'ffmpeg') {
139
-			if ($this->useHdr($absPath)) {
140
-				// Force colorspace to '2020_ncl' because some videos are
141
-				// tagged incorrectly as 'reserved' resulting in fail if not forced.
142
-				$cmd = [$this->binary, '-y', '-ss', (string)$second,
143
-					'-i', $absPath,
144
-					'-f', 'mjpeg', '-vframes', '1',
145
-					'-vf', 'zscale=min=2020_ncl:t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=hable:desat=0,zscale=t=bt709:m=bt709:r=tv,format=yuv420p',
146
-					$tmpPath];
147
-			} else {
148
-				// always default to generating preview using non-HDR command
149
-				$cmd = [$this->binary, '-y', '-ss', (string)$second,
150
-					'-i', $absPath,
151
-					'-f', 'mjpeg', '-vframes', '1',
152
-					$tmpPath];
153
-			}
154
-		} else {
155
-			// Not supported
156
-			unlink($tmpPath);
157
-			return null;
158
-		}
159
-
160
-		$proc = proc_open($cmd, [1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $pipes);
161
-		$returnCode = -1;
162
-		$output = '';
163
-		if (is_resource($proc)) {
164
-			$stderr = trim(stream_get_contents($pipes[2]));
165
-			$stdout = trim(stream_get_contents($pipes[1]));
166
-			$returnCode = proc_close($proc);
167
-			$output = $stdout . $stderr;
168
-		}
169
-
170
-		if ($returnCode === 0) {
171
-			$image = new \OCP\Image();
172
-			$image->loadFromFile($tmpPath);
173
-			if ($image->valid()) {
174
-				unlink($tmpPath);
175
-				$image->scaleDownToFit($maxX, $maxY);
176
-
177
-				return $image;
178
-			}
179
-		}
180
-
181
-		if ($second === 0) {
182
-			$logger = Server::get(LoggerInterface::class);
183
-			$logger->info('Movie preview generation failed Output: {output}', ['app' => 'core', 'output' => $output]);
184
-		}
185
-
186
-		unlink($tmpPath);
187
-		return null;
188
-	}
20
+    private IConfig $config;
21
+
22
+    private ?string $binary = null;
23
+
24
+    public function __construct(array $options = []) {
25
+        parent::__construct($options);
26
+        $this->config = Server::get(IConfig::class);
27
+    }
28
+
29
+    public function getMimeType(): string {
30
+        return '/video\/.*/';
31
+    }
32
+
33
+    /**
34
+     * {@inheritDoc}
35
+     */
36
+    public function isAvailable(FileInfo $file): bool {
37
+        if (is_null($this->binary)) {
38
+            if (isset($this->options['movieBinary'])) {
39
+                $this->binary = $this->options['movieBinary'];
40
+            }
41
+        }
42
+        return is_string($this->binary);
43
+    }
44
+
45
+    /**
46
+     * {@inheritDoc}
47
+     */
48
+    public function getThumbnail(File $file, int $maxX, int $maxY): ?IImage {
49
+        // TODO: use proc_open() and stream the source file ?
50
+
51
+        if (!$this->isAvailable($file)) {
52
+            return null;
53
+        }
54
+
55
+        $result = null;
56
+        if ($this->useTempFile($file)) {
57
+            // Try downloading 5 MB first, as it's likely that the first frames are present there.
58
+            // In some cases this doesn't work, for example when the moov atom is at the
59
+            // end of the file, so if it fails we fall back to getting the full file.
60
+            // Unless the file is not local (e.g. S3) as we do not want to download the whole (e.g. 37Gb) file
61
+            if ($file->getStorage()->isLocal()) {
62
+                $sizeAttempts = [5242880, null];
63
+            } else {
64
+                $sizeAttempts = [5242880];
65
+            }
66
+        } else {
67
+            // size is irrelevant, only attempt once
68
+            $sizeAttempts = [null];
69
+        }
70
+
71
+        foreach ($sizeAttempts as $size) {
72
+            $absPath = $this->getLocalFile($file, $size);
73
+            if ($absPath === false) {
74
+                Server::get(LoggerInterface::class)->error(
75
+                    'Failed to get local file to generate thumbnail for: ' . $file->getPath(),
76
+                    ['app' => 'core']
77
+                );
78
+                return null;
79
+            }
80
+
81
+            $result = $this->generateThumbNail($maxX, $maxY, $absPath, 5);
82
+            if ($result === null) {
83
+                $result = $this->generateThumbNail($maxX, $maxY, $absPath, 1);
84
+                if ($result === null) {
85
+                    $result = $this->generateThumbNail($maxX, $maxY, $absPath, 0);
86
+                }
87
+            }
88
+
89
+            $this->cleanTmpFiles();
90
+
91
+            if ($result !== null) {
92
+                break;
93
+            }
94
+        }
95
+
96
+        return $result;
97
+    }
98
+
99
+    private function useHdr(string $absPath): bool {
100
+        // load ffprobe path from configuration, otherwise generate binary path using ffmpeg binary path
101
+        $ffprobe_binary = $this->config->getSystemValue('preview_ffprobe_path', null) ?? (pathinfo($this->binary, PATHINFO_DIRNAME) . '/ffprobe');
102
+        // run ffprobe on the video file to get value of "color_transfer"
103
+        $test_hdr_cmd = [$ffprobe_binary,'-select_streams', 'v:0',
104
+            '-show_entries', 'stream=color_transfer',
105
+            '-of', 'default=noprint_wrappers=1:nokey=1',
106
+            $absPath];
107
+        $test_hdr_proc = proc_open($test_hdr_cmd, [1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $test_hdr_pipes);
108
+        if ($test_hdr_proc === false) {
109
+            return false;
110
+        }
111
+        $test_hdr_stdout = trim(stream_get_contents($test_hdr_pipes[1]));
112
+        $test_hdr_stderr = trim(stream_get_contents($test_hdr_pipes[2]));
113
+        proc_close($test_hdr_proc);
114
+        // search build options for libzimg (provides zscale filter)
115
+        $ffmpeg_libzimg_installed = strpos($test_hdr_stderr, '--enable-libzimg');
116
+        // Only values of "smpte2084" and "arib-std-b67" indicate an HDR video.
117
+        // Only return true if video is detected as HDR and libzimg is installed.
118
+        if (($test_hdr_stdout === 'smpte2084' || $test_hdr_stdout === 'arib-std-b67') && $ffmpeg_libzimg_installed !== false) {
119
+            return true;
120
+        } else {
121
+            return false;
122
+        }
123
+    }
124
+
125
+    private function generateThumbNail(int $maxX, int $maxY, string $absPath, int $second): ?IImage {
126
+        $tmpPath = Server::get(ITempManager::class)->getTemporaryFile();
127
+
128
+        if ($tmpPath === false) {
129
+            Server::get(LoggerInterface::class)->error(
130
+                'Failed to get local file to generate thumbnail for: ' . $absPath,
131
+                ['app' => 'core']
132
+            );
133
+            return null;
134
+        }
135
+
136
+        $binaryType = substr(strrchr($this->binary, '/'), 1);
137
+
138
+        if ($binaryType === 'ffmpeg') {
139
+            if ($this->useHdr($absPath)) {
140
+                // Force colorspace to '2020_ncl' because some videos are
141
+                // tagged incorrectly as 'reserved' resulting in fail if not forced.
142
+                $cmd = [$this->binary, '-y', '-ss', (string)$second,
143
+                    '-i', $absPath,
144
+                    '-f', 'mjpeg', '-vframes', '1',
145
+                    '-vf', 'zscale=min=2020_ncl:t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=hable:desat=0,zscale=t=bt709:m=bt709:r=tv,format=yuv420p',
146
+                    $tmpPath];
147
+            } else {
148
+                // always default to generating preview using non-HDR command
149
+                $cmd = [$this->binary, '-y', '-ss', (string)$second,
150
+                    '-i', $absPath,
151
+                    '-f', 'mjpeg', '-vframes', '1',
152
+                    $tmpPath];
153
+            }
154
+        } else {
155
+            // Not supported
156
+            unlink($tmpPath);
157
+            return null;
158
+        }
159
+
160
+        $proc = proc_open($cmd, [1 => ['pipe', 'w'], 2 => ['pipe', 'w']], $pipes);
161
+        $returnCode = -1;
162
+        $output = '';
163
+        if (is_resource($proc)) {
164
+            $stderr = trim(stream_get_contents($pipes[2]));
165
+            $stdout = trim(stream_get_contents($pipes[1]));
166
+            $returnCode = proc_close($proc);
167
+            $output = $stdout . $stderr;
168
+        }
169
+
170
+        if ($returnCode === 0) {
171
+            $image = new \OCP\Image();
172
+            $image->loadFromFile($tmpPath);
173
+            if ($image->valid()) {
174
+                unlink($tmpPath);
175
+                $image->scaleDownToFit($maxX, $maxY);
176
+
177
+                return $image;
178
+            }
179
+        }
180
+
181
+        if ($second === 0) {
182
+            $logger = Server::get(LoggerInterface::class);
183
+            $logger->info('Movie preview generation failed Output: {output}', ['app' => 'core', 'output' => $output]);
184
+        }
185
+
186
+        unlink($tmpPath);
187
+        return null;
188
+    }
189 189
 }
Please login to merge, or discard this patch.
Spacing   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -72,7 +72,7 @@  discard block
 block discarded – undo
72 72
 			$absPath = $this->getLocalFile($file, $size);
73 73
 			if ($absPath === false) {
74 74
 				Server::get(LoggerInterface::class)->error(
75
-					'Failed to get local file to generate thumbnail for: ' . $file->getPath(),
75
+					'Failed to get local file to generate thumbnail for: '.$file->getPath(),
76 76
 					['app' => 'core']
77 77
 				);
78 78
 				return null;
@@ -98,9 +98,9 @@  discard block
 block discarded – undo
98 98
 
99 99
 	private function useHdr(string $absPath): bool {
100 100
 		// load ffprobe path from configuration, otherwise generate binary path using ffmpeg binary path
101
-		$ffprobe_binary = $this->config->getSystemValue('preview_ffprobe_path', null) ?? (pathinfo($this->binary, PATHINFO_DIRNAME) . '/ffprobe');
101
+		$ffprobe_binary = $this->config->getSystemValue('preview_ffprobe_path', null) ?? (pathinfo($this->binary, PATHINFO_DIRNAME).'/ffprobe');
102 102
 		// run ffprobe on the video file to get value of "color_transfer"
103
-		$test_hdr_cmd = [$ffprobe_binary,'-select_streams', 'v:0',
103
+		$test_hdr_cmd = [$ffprobe_binary, '-select_streams', 'v:0',
104 104
 			'-show_entries', 'stream=color_transfer',
105 105
 			'-of', 'default=noprint_wrappers=1:nokey=1',
106 106
 			$absPath];
@@ -127,7 +127,7 @@  discard block
 block discarded – undo
127 127
 
128 128
 		if ($tmpPath === false) {
129 129
 			Server::get(LoggerInterface::class)->error(
130
-				'Failed to get local file to generate thumbnail for: ' . $absPath,
130
+				'Failed to get local file to generate thumbnail for: '.$absPath,
131 131
 				['app' => 'core']
132 132
 			);
133 133
 			return null;
@@ -139,14 +139,14 @@  discard block
 block discarded – undo
139 139
 			if ($this->useHdr($absPath)) {
140 140
 				// Force colorspace to '2020_ncl' because some videos are
141 141
 				// tagged incorrectly as 'reserved' resulting in fail if not forced.
142
-				$cmd = [$this->binary, '-y', '-ss', (string)$second,
142
+				$cmd = [$this->binary, '-y', '-ss', (string) $second,
143 143
 					'-i', $absPath,
144 144
 					'-f', 'mjpeg', '-vframes', '1',
145 145
 					'-vf', 'zscale=min=2020_ncl:t=linear:npl=100,format=gbrpf32le,zscale=p=bt709,tonemap=tonemap=hable:desat=0,zscale=t=bt709:m=bt709:r=tv,format=yuv420p',
146 146
 					$tmpPath];
147 147
 			} else {
148 148
 				// always default to generating preview using non-HDR command
149
-				$cmd = [$this->binary, '-y', '-ss', (string)$second,
149
+				$cmd = [$this->binary, '-y', '-ss', (string) $second,
150 150
 					'-i', $absPath,
151 151
 					'-f', 'mjpeg', '-vframes', '1',
152 152
 					$tmpPath];
@@ -164,7 +164,7 @@  discard block
 block discarded – undo
164 164
 			$stderr = trim(stream_get_contents($pipes[2]));
165 165
 			$stdout = trim(stream_get_contents($pipes[1]));
166 166
 			$returnCode = proc_close($proc);
167
-			$output = $stdout . $stderr;
167
+			$output = $stdout.$stderr;
168 168
 		}
169 169
 
170 170
 		if ($returnCode === 0) {
Please login to merge, or discard this patch.
lib/private/PreviewManager.php 1 patch
Indentation   +431 added lines, -431 removed lines patch added patch discarded remove patch
@@ -28,435 +28,435 @@
 block discarded – undo
28 28
 use function array_key_exists;
29 29
 
30 30
 class PreviewManager implements IPreview {
31
-	protected IConfig $config;
32
-	protected IRootFolder $rootFolder;
33
-	protected IAppData $appData;
34
-	protected IEventDispatcher $eventDispatcher;
35
-	private ?Generator $generator = null;
36
-	private GeneratorHelper $helper;
37
-	protected bool $providerListDirty = false;
38
-	protected bool $registeredCoreProviders = false;
39
-	protected array $providers = [];
40
-
41
-	/** @var array mime type => support status */
42
-	protected array $mimeTypeSupportMap = [];
43
-	protected ?array $defaultProviders = null;
44
-	protected ?string $userId;
45
-	private Coordinator $bootstrapCoordinator;
46
-
47
-	/**
48
-	 * Hash map (without value) of loaded bootstrap providers
49
-	 * @psalm-var array<string, null>
50
-	 */
51
-	private array $loadedBootstrapProviders = [];
52
-	private ContainerInterface $container;
53
-	private IBinaryFinder $binaryFinder;
54
-	private IMagickSupport $imagickSupport;
55
-	private bool $enablePreviews;
56
-
57
-	public function __construct(
58
-		IConfig $config,
59
-		IRootFolder $rootFolder,
60
-		IAppData $appData,
61
-		IEventDispatcher $eventDispatcher,
62
-		GeneratorHelper $helper,
63
-		?string $userId,
64
-		Coordinator $bootstrapCoordinator,
65
-		ContainerInterface $container,
66
-		IBinaryFinder $binaryFinder,
67
-		IMagickSupport $imagickSupport,
68
-	) {
69
-		$this->config = $config;
70
-		$this->rootFolder = $rootFolder;
71
-		$this->appData = $appData;
72
-		$this->eventDispatcher = $eventDispatcher;
73
-		$this->helper = $helper;
74
-		$this->userId = $userId;
75
-		$this->bootstrapCoordinator = $bootstrapCoordinator;
76
-		$this->container = $container;
77
-		$this->binaryFinder = $binaryFinder;
78
-		$this->imagickSupport = $imagickSupport;
79
-		$this->enablePreviews = $config->getSystemValueBool('enable_previews', true);
80
-	}
81
-
82
-	/**
83
-	 * In order to improve lazy loading a closure can be registered which will be
84
-	 * called in case preview providers are actually requested
85
-	 *
86
-	 * $callable has to return an instance of \OCP\Preview\IProvider or \OCP\Preview\IProviderV2
87
-	 *
88
-	 * @param string $mimeTypeRegex Regex with the mime types that are supported by this provider
89
-	 * @param \Closure $callable
90
-	 * @return void
91
-	 */
92
-	public function registerProvider($mimeTypeRegex, \Closure $callable): void {
93
-		if (!$this->enablePreviews) {
94
-			return;
95
-		}
96
-
97
-		if (!isset($this->providers[$mimeTypeRegex])) {
98
-			$this->providers[$mimeTypeRegex] = [];
99
-		}
100
-		$this->providers[$mimeTypeRegex][] = $callable;
101
-		$this->providerListDirty = true;
102
-	}
103
-
104
-	/**
105
-	 * Get all providers
106
-	 */
107
-	public function getProviders(): array {
108
-		if (!$this->enablePreviews) {
109
-			return [];
110
-		}
111
-
112
-		$this->registerCoreProviders();
113
-		$this->registerBootstrapProviders();
114
-		if ($this->providerListDirty) {
115
-			$keys = array_map('strlen', array_keys($this->providers));
116
-			array_multisort($keys, SORT_DESC, $this->providers);
117
-			$this->providerListDirty = false;
118
-		}
119
-
120
-		return $this->providers;
121
-	}
122
-
123
-	/**
124
-	 * Does the manager have any providers
125
-	 */
126
-	public function hasProviders(): bool {
127
-		$this->registerCoreProviders();
128
-		return !empty($this->providers);
129
-	}
130
-
131
-	private function getGenerator(): Generator {
132
-		if ($this->generator === null) {
133
-			$this->generator = new Generator(
134
-				$this->config,
135
-				$this,
136
-				$this->appData,
137
-				new GeneratorHelper(
138
-					$this->rootFolder,
139
-					$this->config
140
-				),
141
-				$this->eventDispatcher,
142
-				$this->container->get(LoggerInterface::class),
143
-			);
144
-		}
145
-		return $this->generator;
146
-	}
147
-
148
-	public function getPreview(
149
-		File $file,
150
-		$width = -1,
151
-		$height = -1,
152
-		$crop = false,
153
-		$mode = IPreview::MODE_FILL,
154
-		$mimeType = null,
155
-		bool $cacheResult = true,
156
-	): ISimpleFile {
157
-		$this->throwIfPreviewsDisabled($file, $mimeType);
158
-		$previewConcurrency = $this->getGenerator()->getNumConcurrentPreviews('preview_concurrency_all');
159
-		$sem = Generator::guardWithSemaphore(Generator::SEMAPHORE_ID_ALL, $previewConcurrency);
160
-		try {
161
-			$preview = $this->getGenerator()->getPreview($file, $width, $height, $crop, $mode, $mimeType, $cacheResult);
162
-		} finally {
163
-			Generator::unguardWithSemaphore($sem);
164
-		}
165
-
166
-		return $preview;
167
-	}
168
-
169
-	/**
170
-	 * Generates previews of a file
171
-	 *
172
-	 * @param File $file
173
-	 * @param array $specifications
174
-	 * @param string $mimeType
175
-	 * @return ISimpleFile the last preview that was generated
176
-	 * @throws NotFoundException
177
-	 * @throws \InvalidArgumentException if the preview would be invalid (in case the original image is invalid)
178
-	 * @since 19.0.0
179
-	 */
180
-	public function generatePreviews(File $file, array $specifications, $mimeType = null) {
181
-		$this->throwIfPreviewsDisabled($file, $mimeType);
182
-		return $this->getGenerator()->generatePreviews($file, $specifications, $mimeType);
183
-	}
184
-
185
-	/**
186
-	 * returns true if the passed mime type is supported
187
-	 *
188
-	 * @param string $mimeType
189
-	 * @return boolean
190
-	 */
191
-	public function isMimeSupported($mimeType = '*') {
192
-		if (!$this->enablePreviews) {
193
-			return false;
194
-		}
195
-
196
-		if (isset($this->mimeTypeSupportMap[$mimeType])) {
197
-			return $this->mimeTypeSupportMap[$mimeType];
198
-		}
199
-
200
-		$this->registerCoreProviders();
201
-		$this->registerBootstrapProviders();
202
-		$providerMimeTypes = array_keys($this->providers);
203
-		foreach ($providerMimeTypes as $supportedMimeType) {
204
-			if (preg_match($supportedMimeType, $mimeType)) {
205
-				$this->mimeTypeSupportMap[$mimeType] = true;
206
-				return true;
207
-			}
208
-		}
209
-		$this->mimeTypeSupportMap[$mimeType] = false;
210
-		return false;
211
-	}
212
-
213
-	/**
214
-	 * Check if a preview can be generated for a file
215
-	 */
216
-	public function isAvailable(\OCP\Files\FileInfo $file, ?string $mimeType = null): bool {
217
-		if (!$this->enablePreviews) {
218
-			return false;
219
-		}
220
-
221
-		$fileMimeType = $mimeType ?? $file->getMimeType();
222
-
223
-		$this->registerCoreProviders();
224
-		if (!$this->isMimeSupported($fileMimeType)) {
225
-			return false;
226
-		}
227
-
228
-		$mount = $file->getMountPoint();
229
-		if ($mount and !$mount->getOption('previews', true)) {
230
-			return false;
231
-		}
232
-
233
-		foreach ($this->providers as $supportedMimeType => $providers) {
234
-			if (preg_match($supportedMimeType, $fileMimeType)) {
235
-				foreach ($providers as $providerClosure) {
236
-					$provider = $this->helper->getProvider($providerClosure);
237
-					if (!($provider instanceof IProviderV2)) {
238
-						continue;
239
-					}
240
-
241
-					if ($provider->isAvailable($file)) {
242
-						return true;
243
-					}
244
-				}
245
-			}
246
-		}
247
-		return false;
248
-	}
249
-
250
-	/**
251
-	 * List of enabled default providers
252
-	 *
253
-	 * The following providers are enabled by default:
254
-	 *  - OC\Preview\PNG
255
-	 *  - OC\Preview\JPEG
256
-	 *  - OC\Preview\GIF
257
-	 *  - OC\Preview\BMP
258
-	 *  - OC\Preview\XBitmap
259
-	 *  - OC\Preview\MarkDown
260
-	 *  - OC\Preview\MP3
261
-	 *  - OC\Preview\TXT
262
-	 *
263
-	 * The following providers are disabled by default due to performance or privacy concerns:
264
-	 *  - OC\Preview\Font
265
-	 *  - OC\Preview\HEIC
266
-	 *  - OC\Preview\Illustrator
267
-	 *  - OC\Preview\Movie
268
-	 *  - OC\Preview\MSOfficeDoc
269
-	 *  - OC\Preview\MSOffice2003
270
-	 *  - OC\Preview\MSOffice2007
271
-	 *  - OC\Preview\OpenDocument
272
-	 *  - OC\Preview\PDF
273
-	 *  - OC\Preview\Photoshop
274
-	 *  - OC\Preview\Postscript
275
-	 *  - OC\Preview\StarOffice
276
-	 *  - OC\Preview\SVG
277
-	 *  - OC\Preview\TIFF
278
-	 *
279
-	 * @return array
280
-	 */
281
-	protected function getEnabledDefaultProvider() {
282
-		if ($this->defaultProviders !== null) {
283
-			return $this->defaultProviders;
284
-		}
285
-
286
-		$imageProviders = [
287
-			Preview\PNG::class,
288
-			Preview\JPEG::class,
289
-			Preview\GIF::class,
290
-			Preview\BMP::class,
291
-			Preview\XBitmap::class,
292
-			Preview\Krita::class,
293
-			Preview\WebP::class,
294
-		];
295
-
296
-		$this->defaultProviders = $this->config->getSystemValue('enabledPreviewProviders', array_merge([
297
-			Preview\MarkDown::class,
298
-			Preview\MP3::class,
299
-			Preview\TXT::class,
300
-			Preview\OpenDocument::class,
301
-		], $imageProviders));
302
-
303
-		if (in_array(Preview\Image::class, $this->defaultProviders)) {
304
-			$this->defaultProviders = array_merge($this->defaultProviders, $imageProviders);
305
-		}
306
-		$this->defaultProviders = array_unique($this->defaultProviders);
307
-		return $this->defaultProviders;
308
-	}
309
-
310
-	/**
311
-	 * Register the default providers (if enabled)
312
-	 *
313
-	 * @param string $class
314
-	 * @param string $mimeType
315
-	 */
316
-	protected function registerCoreProvider($class, $mimeType, $options = []) {
317
-		if (in_array(trim($class, '\\'), $this->getEnabledDefaultProvider())) {
318
-			$this->registerProvider($mimeType, function () use ($class, $options) {
319
-				return new $class($options);
320
-			});
321
-		}
322
-	}
323
-
324
-	/**
325
-	 * Register the default providers (if enabled)
326
-	 */
327
-	protected function registerCoreProviders() {
328
-		if ($this->registeredCoreProviders) {
329
-			return;
330
-		}
331
-		$this->registeredCoreProviders = true;
332
-
333
-		$this->registerCoreProvider(Preview\TXT::class, '/text\/plain/');
334
-		$this->registerCoreProvider(Preview\MarkDown::class, '/text\/(x-)?markdown/');
335
-		$this->registerCoreProvider(Preview\PNG::class, '/image\/png/');
336
-		$this->registerCoreProvider(Preview\JPEG::class, '/image\/jpeg/');
337
-		$this->registerCoreProvider(Preview\GIF::class, '/image\/gif/');
338
-		$this->registerCoreProvider(Preview\BMP::class, '/image\/bmp/');
339
-		$this->registerCoreProvider(Preview\XBitmap::class, '/image\/x-xbitmap/');
340
-		$this->registerCoreProvider(Preview\WebP::class, '/image\/webp/');
341
-		$this->registerCoreProvider(Preview\Krita::class, '/application\/x-krita/');
342
-		$this->registerCoreProvider(Preview\MP3::class, '/audio\/mpeg$/');
343
-		$this->registerCoreProvider(Preview\OpenDocument::class, '/application\/vnd.oasis.opendocument.*/');
344
-		$this->registerCoreProvider(Preview\Imaginary::class, Preview\Imaginary::supportedMimeTypes());
345
-		$this->registerCoreProvider(Preview\ImaginaryPDF::class, Preview\ImaginaryPDF::supportedMimeTypes());
346
-
347
-		// SVG and Bitmap require imagick
348
-		if ($this->imagickSupport->hasExtension()) {
349
-			$imagickProviders = [
350
-				'SVG' => ['mimetype' => '/image\/svg\+xml/', 'class' => Preview\SVG::class],
351
-				'TIFF' => ['mimetype' => '/image\/tiff/', 'class' => Preview\TIFF::class],
352
-				'PDF' => ['mimetype' => '/application\/pdf/', 'class' => Preview\PDF::class],
353
-				'AI' => ['mimetype' => '/application\/illustrator/', 'class' => Preview\Illustrator::class],
354
-				'PSD' => ['mimetype' => '/application\/x-photoshop/', 'class' => Preview\Photoshop::class],
355
-				'EPS' => ['mimetype' => '/application\/postscript/', 'class' => Preview\Postscript::class],
356
-				'TTF' => ['mimetype' => '/application\/(?:font-sfnt|x-font$)/', 'class' => Preview\Font::class],
357
-				'HEIC' => ['mimetype' => '/image\/(x-)?hei(f|c)/', 'class' => Preview\HEIC::class],
358
-				'TGA' => ['mimetype' => '/image\/(x-)?t(ar)?ga/', 'class' => Preview\TGA::class],
359
-				'SGI' => ['mimetype' => '/image\/(x-)?sgi/', 'class' => Preview\SGI::class],
360
-			];
361
-
362
-			foreach ($imagickProviders as $queryFormat => $provider) {
363
-				$class = $provider['class'];
364
-				if (!in_array(trim($class, '\\'), $this->getEnabledDefaultProvider())) {
365
-					continue;
366
-				}
367
-
368
-				if ($this->imagickSupport->supportsFormat($queryFormat)) {
369
-					$this->registerCoreProvider($class, $provider['mimetype']);
370
-				}
371
-			}
372
-		}
373
-
374
-		$this->registerCoreProvidersOffice();
375
-
376
-		// Video requires ffmpeg
377
-		if (in_array(Preview\Movie::class, $this->getEnabledDefaultProvider())) {
378
-			$movieBinary = $this->config->getSystemValue('preview_ffmpeg_path', null);
379
-			if (!is_string($movieBinary)) {
380
-				$movieBinary = $this->binaryFinder->findBinaryPath('ffmpeg');
381
-			}
382
-
383
-
384
-			if (is_string($movieBinary)) {
385
-				$this->registerCoreProvider(Preview\Movie::class, '/video\/.*/', ['movieBinary' => $movieBinary]);
386
-			}
387
-		}
388
-	}
389
-
390
-	private function registerCoreProvidersOffice(): void {
391
-		$officeProviders = [
392
-			['mimetype' => '/application\/msword/', 'class' => Preview\MSOfficeDoc::class],
393
-			['mimetype' => '/application\/vnd.ms-.*/', 'class' => Preview\MSOffice2003::class],
394
-			['mimetype' => '/application\/vnd.openxmlformats-officedocument.*/', 'class' => Preview\MSOffice2007::class],
395
-			['mimetype' => '/application\/vnd.oasis.opendocument.*/', 'class' => Preview\OpenDocument::class],
396
-			['mimetype' => '/application\/vnd.sun.xml.*/', 'class' => Preview\StarOffice::class],
397
-			['mimetype' => '/image\/emf/', 'class' => Preview\EMF::class],
398
-		];
399
-
400
-		$findBinary = true;
401
-		$officeBinary = false;
402
-
403
-		foreach ($officeProviders as $provider) {
404
-			$class = $provider['class'];
405
-			if (!in_array(trim($class, '\\'), $this->getEnabledDefaultProvider())) {
406
-				continue;
407
-			}
408
-
409
-			if ($findBinary) {
410
-				// Office requires openoffice or libreoffice
411
-				$officeBinary = $this->config->getSystemValue('preview_libreoffice_path', false);
412
-				if ($officeBinary === false) {
413
-					$officeBinary = $this->binaryFinder->findBinaryPath('libreoffice');
414
-				}
415
-				if ($officeBinary === false) {
416
-					$officeBinary = $this->binaryFinder->findBinaryPath('openoffice');
417
-				}
418
-				$findBinary = false;
419
-			}
420
-
421
-			if ($officeBinary) {
422
-				$this->registerCoreProvider($class, $provider['mimetype'], ['officeBinary' => $officeBinary]);
423
-			}
424
-		}
425
-	}
426
-
427
-	private function registerBootstrapProviders(): void {
428
-		$context = $this->bootstrapCoordinator->getRegistrationContext();
429
-
430
-		if ($context === null) {
431
-			// Just ignore for now
432
-			return;
433
-		}
434
-
435
-		$providers = $context->getPreviewProviders();
436
-		foreach ($providers as $provider) {
437
-			$key = $provider->getMimeTypeRegex() . '-' . $provider->getService();
438
-			if (array_key_exists($key, $this->loadedBootstrapProviders)) {
439
-				// Do not load the provider more than once
440
-				continue;
441
-			}
442
-			$this->loadedBootstrapProviders[$key] = null;
443
-
444
-			$this->registerProvider($provider->getMimeTypeRegex(), function () use ($provider) {
445
-				try {
446
-					return $this->container->get($provider->getService());
447
-				} catch (QueryException $e) {
448
-					return null;
449
-				}
450
-			});
451
-		}
452
-	}
453
-
454
-	/**
455
-	 * @throws NotFoundException if preview generation is disabled
456
-	 */
457
-	private function throwIfPreviewsDisabled(File $file, ?string $mimeType = null): void {
458
-		if (!$this->isAvailable($file, $mimeType)) {
459
-			throw new NotFoundException('Previews disabled');
460
-		}
461
-	}
31
+    protected IConfig $config;
32
+    protected IRootFolder $rootFolder;
33
+    protected IAppData $appData;
34
+    protected IEventDispatcher $eventDispatcher;
35
+    private ?Generator $generator = null;
36
+    private GeneratorHelper $helper;
37
+    protected bool $providerListDirty = false;
38
+    protected bool $registeredCoreProviders = false;
39
+    protected array $providers = [];
40
+
41
+    /** @var array mime type => support status */
42
+    protected array $mimeTypeSupportMap = [];
43
+    protected ?array $defaultProviders = null;
44
+    protected ?string $userId;
45
+    private Coordinator $bootstrapCoordinator;
46
+
47
+    /**
48
+     * Hash map (without value) of loaded bootstrap providers
49
+     * @psalm-var array<string, null>
50
+     */
51
+    private array $loadedBootstrapProviders = [];
52
+    private ContainerInterface $container;
53
+    private IBinaryFinder $binaryFinder;
54
+    private IMagickSupport $imagickSupport;
55
+    private bool $enablePreviews;
56
+
57
+    public function __construct(
58
+        IConfig $config,
59
+        IRootFolder $rootFolder,
60
+        IAppData $appData,
61
+        IEventDispatcher $eventDispatcher,
62
+        GeneratorHelper $helper,
63
+        ?string $userId,
64
+        Coordinator $bootstrapCoordinator,
65
+        ContainerInterface $container,
66
+        IBinaryFinder $binaryFinder,
67
+        IMagickSupport $imagickSupport,
68
+    ) {
69
+        $this->config = $config;
70
+        $this->rootFolder = $rootFolder;
71
+        $this->appData = $appData;
72
+        $this->eventDispatcher = $eventDispatcher;
73
+        $this->helper = $helper;
74
+        $this->userId = $userId;
75
+        $this->bootstrapCoordinator = $bootstrapCoordinator;
76
+        $this->container = $container;
77
+        $this->binaryFinder = $binaryFinder;
78
+        $this->imagickSupport = $imagickSupport;
79
+        $this->enablePreviews = $config->getSystemValueBool('enable_previews', true);
80
+    }
81
+
82
+    /**
83
+     * In order to improve lazy loading a closure can be registered which will be
84
+     * called in case preview providers are actually requested
85
+     *
86
+     * $callable has to return an instance of \OCP\Preview\IProvider or \OCP\Preview\IProviderV2
87
+     *
88
+     * @param string $mimeTypeRegex Regex with the mime types that are supported by this provider
89
+     * @param \Closure $callable
90
+     * @return void
91
+     */
92
+    public function registerProvider($mimeTypeRegex, \Closure $callable): void {
93
+        if (!$this->enablePreviews) {
94
+            return;
95
+        }
96
+
97
+        if (!isset($this->providers[$mimeTypeRegex])) {
98
+            $this->providers[$mimeTypeRegex] = [];
99
+        }
100
+        $this->providers[$mimeTypeRegex][] = $callable;
101
+        $this->providerListDirty = true;
102
+    }
103
+
104
+    /**
105
+     * Get all providers
106
+     */
107
+    public function getProviders(): array {
108
+        if (!$this->enablePreviews) {
109
+            return [];
110
+        }
111
+
112
+        $this->registerCoreProviders();
113
+        $this->registerBootstrapProviders();
114
+        if ($this->providerListDirty) {
115
+            $keys = array_map('strlen', array_keys($this->providers));
116
+            array_multisort($keys, SORT_DESC, $this->providers);
117
+            $this->providerListDirty = false;
118
+        }
119
+
120
+        return $this->providers;
121
+    }
122
+
123
+    /**
124
+     * Does the manager have any providers
125
+     */
126
+    public function hasProviders(): bool {
127
+        $this->registerCoreProviders();
128
+        return !empty($this->providers);
129
+    }
130
+
131
+    private function getGenerator(): Generator {
132
+        if ($this->generator === null) {
133
+            $this->generator = new Generator(
134
+                $this->config,
135
+                $this,
136
+                $this->appData,
137
+                new GeneratorHelper(
138
+                    $this->rootFolder,
139
+                    $this->config
140
+                ),
141
+                $this->eventDispatcher,
142
+                $this->container->get(LoggerInterface::class),
143
+            );
144
+        }
145
+        return $this->generator;
146
+    }
147
+
148
+    public function getPreview(
149
+        File $file,
150
+        $width = -1,
151
+        $height = -1,
152
+        $crop = false,
153
+        $mode = IPreview::MODE_FILL,
154
+        $mimeType = null,
155
+        bool $cacheResult = true,
156
+    ): ISimpleFile {
157
+        $this->throwIfPreviewsDisabled($file, $mimeType);
158
+        $previewConcurrency = $this->getGenerator()->getNumConcurrentPreviews('preview_concurrency_all');
159
+        $sem = Generator::guardWithSemaphore(Generator::SEMAPHORE_ID_ALL, $previewConcurrency);
160
+        try {
161
+            $preview = $this->getGenerator()->getPreview($file, $width, $height, $crop, $mode, $mimeType, $cacheResult);
162
+        } finally {
163
+            Generator::unguardWithSemaphore($sem);
164
+        }
165
+
166
+        return $preview;
167
+    }
168
+
169
+    /**
170
+     * Generates previews of a file
171
+     *
172
+     * @param File $file
173
+     * @param array $specifications
174
+     * @param string $mimeType
175
+     * @return ISimpleFile the last preview that was generated
176
+     * @throws NotFoundException
177
+     * @throws \InvalidArgumentException if the preview would be invalid (in case the original image is invalid)
178
+     * @since 19.0.0
179
+     */
180
+    public function generatePreviews(File $file, array $specifications, $mimeType = null) {
181
+        $this->throwIfPreviewsDisabled($file, $mimeType);
182
+        return $this->getGenerator()->generatePreviews($file, $specifications, $mimeType);
183
+    }
184
+
185
+    /**
186
+     * returns true if the passed mime type is supported
187
+     *
188
+     * @param string $mimeType
189
+     * @return boolean
190
+     */
191
+    public function isMimeSupported($mimeType = '*') {
192
+        if (!$this->enablePreviews) {
193
+            return false;
194
+        }
195
+
196
+        if (isset($this->mimeTypeSupportMap[$mimeType])) {
197
+            return $this->mimeTypeSupportMap[$mimeType];
198
+        }
199
+
200
+        $this->registerCoreProviders();
201
+        $this->registerBootstrapProviders();
202
+        $providerMimeTypes = array_keys($this->providers);
203
+        foreach ($providerMimeTypes as $supportedMimeType) {
204
+            if (preg_match($supportedMimeType, $mimeType)) {
205
+                $this->mimeTypeSupportMap[$mimeType] = true;
206
+                return true;
207
+            }
208
+        }
209
+        $this->mimeTypeSupportMap[$mimeType] = false;
210
+        return false;
211
+    }
212
+
213
+    /**
214
+     * Check if a preview can be generated for a file
215
+     */
216
+    public function isAvailable(\OCP\Files\FileInfo $file, ?string $mimeType = null): bool {
217
+        if (!$this->enablePreviews) {
218
+            return false;
219
+        }
220
+
221
+        $fileMimeType = $mimeType ?? $file->getMimeType();
222
+
223
+        $this->registerCoreProviders();
224
+        if (!$this->isMimeSupported($fileMimeType)) {
225
+            return false;
226
+        }
227
+
228
+        $mount = $file->getMountPoint();
229
+        if ($mount and !$mount->getOption('previews', true)) {
230
+            return false;
231
+        }
232
+
233
+        foreach ($this->providers as $supportedMimeType => $providers) {
234
+            if (preg_match($supportedMimeType, $fileMimeType)) {
235
+                foreach ($providers as $providerClosure) {
236
+                    $provider = $this->helper->getProvider($providerClosure);
237
+                    if (!($provider instanceof IProviderV2)) {
238
+                        continue;
239
+                    }
240
+
241
+                    if ($provider->isAvailable($file)) {
242
+                        return true;
243
+                    }
244
+                }
245
+            }
246
+        }
247
+        return false;
248
+    }
249
+
250
+    /**
251
+     * List of enabled default providers
252
+     *
253
+     * The following providers are enabled by default:
254
+     *  - OC\Preview\PNG
255
+     *  - OC\Preview\JPEG
256
+     *  - OC\Preview\GIF
257
+     *  - OC\Preview\BMP
258
+     *  - OC\Preview\XBitmap
259
+     *  - OC\Preview\MarkDown
260
+     *  - OC\Preview\MP3
261
+     *  - OC\Preview\TXT
262
+     *
263
+     * The following providers are disabled by default due to performance or privacy concerns:
264
+     *  - OC\Preview\Font
265
+     *  - OC\Preview\HEIC
266
+     *  - OC\Preview\Illustrator
267
+     *  - OC\Preview\Movie
268
+     *  - OC\Preview\MSOfficeDoc
269
+     *  - OC\Preview\MSOffice2003
270
+     *  - OC\Preview\MSOffice2007
271
+     *  - OC\Preview\OpenDocument
272
+     *  - OC\Preview\PDF
273
+     *  - OC\Preview\Photoshop
274
+     *  - OC\Preview\Postscript
275
+     *  - OC\Preview\StarOffice
276
+     *  - OC\Preview\SVG
277
+     *  - OC\Preview\TIFF
278
+     *
279
+     * @return array
280
+     */
281
+    protected function getEnabledDefaultProvider() {
282
+        if ($this->defaultProviders !== null) {
283
+            return $this->defaultProviders;
284
+        }
285
+
286
+        $imageProviders = [
287
+            Preview\PNG::class,
288
+            Preview\JPEG::class,
289
+            Preview\GIF::class,
290
+            Preview\BMP::class,
291
+            Preview\XBitmap::class,
292
+            Preview\Krita::class,
293
+            Preview\WebP::class,
294
+        ];
295
+
296
+        $this->defaultProviders = $this->config->getSystemValue('enabledPreviewProviders', array_merge([
297
+            Preview\MarkDown::class,
298
+            Preview\MP3::class,
299
+            Preview\TXT::class,
300
+            Preview\OpenDocument::class,
301
+        ], $imageProviders));
302
+
303
+        if (in_array(Preview\Image::class, $this->defaultProviders)) {
304
+            $this->defaultProviders = array_merge($this->defaultProviders, $imageProviders);
305
+        }
306
+        $this->defaultProviders = array_unique($this->defaultProviders);
307
+        return $this->defaultProviders;
308
+    }
309
+
310
+    /**
311
+     * Register the default providers (if enabled)
312
+     *
313
+     * @param string $class
314
+     * @param string $mimeType
315
+     */
316
+    protected function registerCoreProvider($class, $mimeType, $options = []) {
317
+        if (in_array(trim($class, '\\'), $this->getEnabledDefaultProvider())) {
318
+            $this->registerProvider($mimeType, function () use ($class, $options) {
319
+                return new $class($options);
320
+            });
321
+        }
322
+    }
323
+
324
+    /**
325
+     * Register the default providers (if enabled)
326
+     */
327
+    protected function registerCoreProviders() {
328
+        if ($this->registeredCoreProviders) {
329
+            return;
330
+        }
331
+        $this->registeredCoreProviders = true;
332
+
333
+        $this->registerCoreProvider(Preview\TXT::class, '/text\/plain/');
334
+        $this->registerCoreProvider(Preview\MarkDown::class, '/text\/(x-)?markdown/');
335
+        $this->registerCoreProvider(Preview\PNG::class, '/image\/png/');
336
+        $this->registerCoreProvider(Preview\JPEG::class, '/image\/jpeg/');
337
+        $this->registerCoreProvider(Preview\GIF::class, '/image\/gif/');
338
+        $this->registerCoreProvider(Preview\BMP::class, '/image\/bmp/');
339
+        $this->registerCoreProvider(Preview\XBitmap::class, '/image\/x-xbitmap/');
340
+        $this->registerCoreProvider(Preview\WebP::class, '/image\/webp/');
341
+        $this->registerCoreProvider(Preview\Krita::class, '/application\/x-krita/');
342
+        $this->registerCoreProvider(Preview\MP3::class, '/audio\/mpeg$/');
343
+        $this->registerCoreProvider(Preview\OpenDocument::class, '/application\/vnd.oasis.opendocument.*/');
344
+        $this->registerCoreProvider(Preview\Imaginary::class, Preview\Imaginary::supportedMimeTypes());
345
+        $this->registerCoreProvider(Preview\ImaginaryPDF::class, Preview\ImaginaryPDF::supportedMimeTypes());
346
+
347
+        // SVG and Bitmap require imagick
348
+        if ($this->imagickSupport->hasExtension()) {
349
+            $imagickProviders = [
350
+                'SVG' => ['mimetype' => '/image\/svg\+xml/', 'class' => Preview\SVG::class],
351
+                'TIFF' => ['mimetype' => '/image\/tiff/', 'class' => Preview\TIFF::class],
352
+                'PDF' => ['mimetype' => '/application\/pdf/', 'class' => Preview\PDF::class],
353
+                'AI' => ['mimetype' => '/application\/illustrator/', 'class' => Preview\Illustrator::class],
354
+                'PSD' => ['mimetype' => '/application\/x-photoshop/', 'class' => Preview\Photoshop::class],
355
+                'EPS' => ['mimetype' => '/application\/postscript/', 'class' => Preview\Postscript::class],
356
+                'TTF' => ['mimetype' => '/application\/(?:font-sfnt|x-font$)/', 'class' => Preview\Font::class],
357
+                'HEIC' => ['mimetype' => '/image\/(x-)?hei(f|c)/', 'class' => Preview\HEIC::class],
358
+                'TGA' => ['mimetype' => '/image\/(x-)?t(ar)?ga/', 'class' => Preview\TGA::class],
359
+                'SGI' => ['mimetype' => '/image\/(x-)?sgi/', 'class' => Preview\SGI::class],
360
+            ];
361
+
362
+            foreach ($imagickProviders as $queryFormat => $provider) {
363
+                $class = $provider['class'];
364
+                if (!in_array(trim($class, '\\'), $this->getEnabledDefaultProvider())) {
365
+                    continue;
366
+                }
367
+
368
+                if ($this->imagickSupport->supportsFormat($queryFormat)) {
369
+                    $this->registerCoreProvider($class, $provider['mimetype']);
370
+                }
371
+            }
372
+        }
373
+
374
+        $this->registerCoreProvidersOffice();
375
+
376
+        // Video requires ffmpeg
377
+        if (in_array(Preview\Movie::class, $this->getEnabledDefaultProvider())) {
378
+            $movieBinary = $this->config->getSystemValue('preview_ffmpeg_path', null);
379
+            if (!is_string($movieBinary)) {
380
+                $movieBinary = $this->binaryFinder->findBinaryPath('ffmpeg');
381
+            }
382
+
383
+
384
+            if (is_string($movieBinary)) {
385
+                $this->registerCoreProvider(Preview\Movie::class, '/video\/.*/', ['movieBinary' => $movieBinary]);
386
+            }
387
+        }
388
+    }
389
+
390
+    private function registerCoreProvidersOffice(): void {
391
+        $officeProviders = [
392
+            ['mimetype' => '/application\/msword/', 'class' => Preview\MSOfficeDoc::class],
393
+            ['mimetype' => '/application\/vnd.ms-.*/', 'class' => Preview\MSOffice2003::class],
394
+            ['mimetype' => '/application\/vnd.openxmlformats-officedocument.*/', 'class' => Preview\MSOffice2007::class],
395
+            ['mimetype' => '/application\/vnd.oasis.opendocument.*/', 'class' => Preview\OpenDocument::class],
396
+            ['mimetype' => '/application\/vnd.sun.xml.*/', 'class' => Preview\StarOffice::class],
397
+            ['mimetype' => '/image\/emf/', 'class' => Preview\EMF::class],
398
+        ];
399
+
400
+        $findBinary = true;
401
+        $officeBinary = false;
402
+
403
+        foreach ($officeProviders as $provider) {
404
+            $class = $provider['class'];
405
+            if (!in_array(trim($class, '\\'), $this->getEnabledDefaultProvider())) {
406
+                continue;
407
+            }
408
+
409
+            if ($findBinary) {
410
+                // Office requires openoffice or libreoffice
411
+                $officeBinary = $this->config->getSystemValue('preview_libreoffice_path', false);
412
+                if ($officeBinary === false) {
413
+                    $officeBinary = $this->binaryFinder->findBinaryPath('libreoffice');
414
+                }
415
+                if ($officeBinary === false) {
416
+                    $officeBinary = $this->binaryFinder->findBinaryPath('openoffice');
417
+                }
418
+                $findBinary = false;
419
+            }
420
+
421
+            if ($officeBinary) {
422
+                $this->registerCoreProvider($class, $provider['mimetype'], ['officeBinary' => $officeBinary]);
423
+            }
424
+        }
425
+    }
426
+
427
+    private function registerBootstrapProviders(): void {
428
+        $context = $this->bootstrapCoordinator->getRegistrationContext();
429
+
430
+        if ($context === null) {
431
+            // Just ignore for now
432
+            return;
433
+        }
434
+
435
+        $providers = $context->getPreviewProviders();
436
+        foreach ($providers as $provider) {
437
+            $key = $provider->getMimeTypeRegex() . '-' . $provider->getService();
438
+            if (array_key_exists($key, $this->loadedBootstrapProviders)) {
439
+                // Do not load the provider more than once
440
+                continue;
441
+            }
442
+            $this->loadedBootstrapProviders[$key] = null;
443
+
444
+            $this->registerProvider($provider->getMimeTypeRegex(), function () use ($provider) {
445
+                try {
446
+                    return $this->container->get($provider->getService());
447
+                } catch (QueryException $e) {
448
+                    return null;
449
+                }
450
+            });
451
+        }
452
+    }
453
+
454
+    /**
455
+     * @throws NotFoundException if preview generation is disabled
456
+     */
457
+    private function throwIfPreviewsDisabled(File $file, ?string $mimeType = null): void {
458
+        if (!$this->isAvailable($file, $mimeType)) {
459
+            throw new NotFoundException('Previews disabled');
460
+        }
461
+    }
462 462
 }
Please login to merge, or discard this patch.
tests/lib/Preview/MovieTest.php 1 patch
Indentation   +14 added lines, -14 removed lines patch added patch discarded remove patch
@@ -20,21 +20,21 @@
 block discarded – undo
20 20
  * @package Test\Preview
21 21
  */
22 22
 class MovieTest extends Provider {
23
-	protected string $fileName = 'testimage.mp4';
24
-	protected int $width = 560;
25
-	protected int $height = 320;
23
+    protected string $fileName = 'testimage.mp4';
24
+    protected int $width = 560;
25
+    protected int $height = 320;
26 26
 
27
-	protected function setUp(): void {
28
-		$binaryFinder = Server::get(IBinaryFinder::class);
29
-		$movieBinary = $binaryFinder->findBinaryPath('ffmpeg');
27
+    protected function setUp(): void {
28
+        $binaryFinder = Server::get(IBinaryFinder::class);
29
+        $movieBinary = $binaryFinder->findBinaryPath('ffmpeg');
30 30
 
31
-		if (is_string($movieBinary)) {
32
-			parent::setUp();
31
+        if (is_string($movieBinary)) {
32
+            parent::setUp();
33 33
 
34
-			$this->imgPath = $this->prepareTestFile($this->fileName, \OC::$SERVERROOT . '/tests/data/' . $this->fileName);
35
-			$this->provider = new Movie(['movieBinary' => $movieBinary]);
36
-		} else {
37
-			$this->markTestSkipped('No Movie provider present');
38
-		}
39
-	}
34
+            $this->imgPath = $this->prepareTestFile($this->fileName, \OC::$SERVERROOT . '/tests/data/' . $this->fileName);
35
+            $this->provider = new Movie(['movieBinary' => $movieBinary]);
36
+        } else {
37
+            $this->markTestSkipped('No Movie provider present');
38
+        }
39
+    }
40 40
 }
Please login to merge, or discard this patch.