Completed
Push — master ( 65f52c...2cb2ff )
by Daniel
37:42
created
lib/private/PreviewManager.php 1 patch
Indentation   +413 added lines, -413 removed lines patch added patch discarded remove patch
@@ -33,417 +33,417 @@
 block discarded – undo
33 33
  * @psalm-import-type ProviderClosure from IPreview
34 34
  */
35 35
 class PreviewManager implements IPreview {
36
-	protected IConfig $config;
37
-	protected IRootFolder $rootFolder;
38
-	protected IEventDispatcher $eventDispatcher;
39
-	private ?Generator $generator = null;
40
-	private GeneratorHelper $helper;
41
-	protected bool $providerListDirty = false;
42
-	protected bool $registeredCoreProviders = false;
43
-	/**
44
-	 * @var array<string, list<ProviderClosure>> $providers
45
-	 */
46
-	protected array $providers = [];
47
-
48
-	/** @var array mime type => support status */
49
-	protected array $mimeTypeSupportMap = [];
50
-	/** @var ?list<class-string<IProviderV2>> $defaultProviders */
51
-	protected ?array $defaultProviders = null;
52
-	protected ?string $userId;
53
-	private Coordinator $bootstrapCoordinator;
54
-
55
-	/**
56
-	 * Hash map (without value) of loaded bootstrap providers
57
-	 * @psalm-var array<string, null>
58
-	 */
59
-	private array $loadedBootstrapProviders = [];
60
-	private ContainerInterface $container;
61
-	private IBinaryFinder $binaryFinder;
62
-	private IMagickSupport $imagickSupport;
63
-	private bool $enablePreviews;
64
-
65
-	public function __construct(
66
-		IConfig $config,
67
-		IRootFolder $rootFolder,
68
-		IEventDispatcher $eventDispatcher,
69
-		GeneratorHelper $helper,
70
-		?string $userId,
71
-		Coordinator $bootstrapCoordinator,
72
-		ContainerInterface $container,
73
-		IBinaryFinder $binaryFinder,
74
-		IMagickSupport $imagickSupport,
75
-	) {
76
-		$this->config = $config;
77
-		$this->rootFolder = $rootFolder;
78
-		$this->eventDispatcher = $eventDispatcher;
79
-		$this->helper = $helper;
80
-		$this->userId = $userId;
81
-		$this->bootstrapCoordinator = $bootstrapCoordinator;
82
-		$this->container = $container;
83
-		$this->binaryFinder = $binaryFinder;
84
-		$this->imagickSupport = $imagickSupport;
85
-		$this->enablePreviews = $config->getSystemValueBool('enable_previews', true);
86
-	}
87
-
88
-	/**
89
-	 * In order to improve lazy loading a closure can be registered which will be
90
-	 * called in case preview providers are actually requested
91
-	 *
92
-	 * @param string $mimeTypeRegex Regex with the mime types that are supported by this provider
93
-	 * @param ProviderClosure $callable
94
-	 */
95
-	public function registerProvider(string $mimeTypeRegex, Closure $callable): void {
96
-		if (!$this->enablePreviews) {
97
-			return;
98
-		}
99
-
100
-		if (!isset($this->providers[$mimeTypeRegex])) {
101
-			$this->providers[$mimeTypeRegex] = [];
102
-		}
103
-		$this->providers[$mimeTypeRegex][] = $callable;
104
-		$this->providerListDirty = true;
105
-	}
106
-
107
-	/**
108
-	 * Get all providers
109
-	 */
110
-	public function getProviders(): array {
111
-		if (!$this->enablePreviews) {
112
-			return [];
113
-		}
114
-
115
-		$this->registerCoreProviders();
116
-		$this->registerBootstrapProviders();
117
-		if ($this->providerListDirty) {
118
-			$keys = array_map('strlen', array_keys($this->providers));
119
-			array_multisort($keys, SORT_DESC, $this->providers);
120
-			$this->providerListDirty = false;
121
-		}
122
-
123
-		return $this->providers;
124
-	}
125
-
126
-	/**
127
-	 * Does the manager have any providers
128
-	 */
129
-	public function hasProviders(): bool {
130
-		$this->registerCoreProviders();
131
-		return !empty($this->providers);
132
-	}
133
-
134
-	private function getGenerator(): Generator {
135
-		if ($this->generator === null) {
136
-			$this->generator = new Generator(
137
-				$this->config,
138
-				$this,
139
-				new GeneratorHelper(),
140
-				$this->eventDispatcher,
141
-				$this->container->get(LoggerInterface::class),
142
-				$this->container->get(PreviewMapper::class),
143
-				$this->container->get(StorageFactory::class),
144
-			);
145
-		}
146
-		return $this->generator;
147
-	}
148
-
149
-	public function getPreview(
150
-		File $file,
151
-		int $width = -1,
152
-		int $height = -1,
153
-		bool $crop = false,
154
-		string $mode = IPreview::MODE_FILL,
155
-		?string $mimeType = null,
156
-		bool $cacheResult = true,
157
-	): ISimpleFile {
158
-		$this->throwIfPreviewsDisabled($file, $mimeType);
159
-		$previewConcurrency = $this->getGenerator()->getNumConcurrentPreviews('preview_concurrency_all');
160
-		$sem = Generator::guardWithSemaphore(Generator::SEMAPHORE_ID_ALL, $previewConcurrency);
161
-		try {
162
-			$preview = $this->getGenerator()->getPreview($file, $width, $height, $crop, $mode, $mimeType, $cacheResult);
163
-		} finally {
164
-			Generator::unguardWithSemaphore($sem);
165
-		}
166
-
167
-		return $preview;
168
-	}
169
-
170
-	/**
171
-	 * Generates previews of a file
172
-	 *
173
-	 * @param array $specifications
174
-	 * @return ISimpleFile the last preview that was generated
175
-	 * @throws NotFoundException
176
-	 * @throws \InvalidArgumentException if the preview would be invalid (in case the original image is invalid)
177
-	 * @since 19.0.0
178
-	 */
179
-	public function generatePreviews(File $file, array $specifications, ?string $mimeType = null): ISimpleFile {
180
-		$this->throwIfPreviewsDisabled($file, $mimeType);
181
-		return $this->getGenerator()->generatePreviews($file, $specifications, $mimeType);
182
-	}
183
-
184
-	public function isMimeSupported(string $mimeType = '*'): bool {
185
-		if (!$this->enablePreviews) {
186
-			return false;
187
-		}
188
-
189
-		if (isset($this->mimeTypeSupportMap[$mimeType])) {
190
-			return $this->mimeTypeSupportMap[$mimeType];
191
-		}
192
-
193
-		$this->registerCoreProviders();
194
-		$this->registerBootstrapProviders();
195
-		$providerMimeTypes = array_keys($this->providers);
196
-		foreach ($providerMimeTypes as $supportedMimeType) {
197
-			if (preg_match($supportedMimeType, $mimeType)) {
198
-				$this->mimeTypeSupportMap[$mimeType] = true;
199
-				return true;
200
-			}
201
-		}
202
-		$this->mimeTypeSupportMap[$mimeType] = false;
203
-		return false;
204
-	}
205
-
206
-	public function isAvailable(\OCP\Files\FileInfo $file, ?string $mimeType = null): bool {
207
-		if (!$this->enablePreviews) {
208
-			return false;
209
-		}
210
-
211
-		$fileMimeType = $mimeType ?? $file->getMimeType();
212
-
213
-		$this->registerCoreProviders();
214
-		if (!$this->isMimeSupported($fileMimeType)) {
215
-			return false;
216
-		}
217
-
218
-		$mount = $file->getMountPoint();
219
-		if ($mount && !$mount->getOption('previews', true)) {
220
-			return false;
221
-		}
222
-
223
-		foreach ($this->providers as $supportedMimeType => $providers) {
224
-			if (preg_match($supportedMimeType, $fileMimeType)) {
225
-				foreach ($providers as $providerClosure) {
226
-					$provider = $this->helper->getProvider($providerClosure);
227
-					if (!$provider) {
228
-						continue;
229
-					}
230
-					if ($provider->isAvailable($file)) {
231
-						return true;
232
-					}
233
-				}
234
-			}
235
-		}
236
-		return false;
237
-	}
238
-
239
-	/**
240
-	 * List of enabled default providers
241
-	 *
242
-	 * The following providers are enabled by default:
243
-	 *  - OC\Preview\BMP
244
-	 *  - OC\Preview\GIF
245
-	 *  - OC\Preview\JPEG
246
-	 *  - OC\Preview\MarkDown
247
-	 *  - OC\Preview\PNG
248
-	 *  - OC\Preview\TXT
249
-	 *  - OC\Preview\XBitmap
250
-	 *
251
-	 * The following providers are disabled by default due to performance or privacy concerns:
252
-	 *  - OC\Preview\Font
253
-	 *  - OC\Preview\HEIC
254
-	 *  - OC\Preview\Illustrator
255
-	 *  - OC\Preview\MP3
256
-	 *  - OC\Preview\MSOffice2003
257
-	 *  - OC\Preview\MSOffice2007
258
-	 *  - OC\Preview\MSOfficeDoc
259
-	 *  - OC\Preview\Movie
260
-	 *  - OC\Preview\OpenDocument
261
-	 *  - OC\Preview\PDF
262
-	 *  - OC\Preview\Photoshop
263
-	 *  - OC\Preview\Postscript
264
-	 *  - OC\Preview\SVG
265
-	 *  - OC\Preview\StarOffice
266
-	 *  - OC\Preview\TIFF
267
-	 *
268
-	 * @return list<class-string<IProviderV2>>
269
-	 */
270
-	protected function getEnabledDefaultProvider(): array {
271
-		if ($this->defaultProviders !== null) {
272
-			return $this->defaultProviders;
273
-		}
274
-
275
-		$imageProviders = [
276
-			Preview\PNG::class,
277
-			Preview\JPEG::class,
278
-			Preview\GIF::class,
279
-			Preview\BMP::class,
280
-			Preview\XBitmap::class,
281
-			Preview\Krita::class,
282
-			Preview\WebP::class,
283
-		];
284
-
285
-		$this->defaultProviders = $this->config->getSystemValue('enabledPreviewProviders', array_merge([
286
-			Preview\MarkDown::class,
287
-			Preview\TXT::class,
288
-			Preview\OpenDocument::class,
289
-		], $imageProviders));
290
-
291
-		if (in_array(Preview\Image::class, $this->defaultProviders)) {
292
-			$this->defaultProviders = array_merge($this->defaultProviders, $imageProviders);
293
-		}
294
-		$this->defaultProviders = array_values(array_unique($this->defaultProviders));
295
-		/** @var list<class-string<IProviderV2>> $providers */
296
-		$providers = $this->defaultProviders;
297
-		return $providers;
298
-	}
299
-
300
-	/**
301
-	 * Register the default providers (if enabled)
302
-	 */
303
-	protected function registerCoreProvider(string $class, string $mimeType, array $options = []): void {
304
-		if (in_array(trim($class, '\\'), $this->getEnabledDefaultProvider())) {
305
-			$this->registerProvider($mimeType, function () use ($class, $options) {
306
-				return new $class($options);
307
-			});
308
-		}
309
-	}
310
-
311
-	/**
312
-	 * Register the default providers (if enabled)
313
-	 */
314
-	protected function registerCoreProviders(): void {
315
-		if ($this->registeredCoreProviders) {
316
-			return;
317
-		}
318
-		$this->registeredCoreProviders = true;
319
-
320
-		$this->registerCoreProvider(Preview\TXT::class, '/text\/plain/');
321
-		$this->registerCoreProvider(Preview\MarkDown::class, '/text\/(x-)?markdown/');
322
-		$this->registerCoreProvider(Preview\PNG::class, '/image\/png/');
323
-		$this->registerCoreProvider(Preview\JPEG::class, '/image\/jpeg/');
324
-		$this->registerCoreProvider(Preview\GIF::class, '/image\/gif/');
325
-		$this->registerCoreProvider(Preview\BMP::class, '/image\/bmp/');
326
-		$this->registerCoreProvider(Preview\XBitmap::class, '/image\/x-xbitmap/');
327
-		$this->registerCoreProvider(Preview\WebP::class, '/image\/webp/');
328
-		$this->registerCoreProvider(Preview\Krita::class, '/application\/x-krita/');
329
-		$this->registerCoreProvider(Preview\MP3::class, '/audio\/mpeg$/');
330
-		$this->registerCoreProvider(Preview\OpenDocument::class, '/application\/vnd.oasis.opendocument.*/');
331
-		$this->registerCoreProvider(Preview\Imaginary::class, Preview\Imaginary::supportedMimeTypes());
332
-		$this->registerCoreProvider(Preview\ImaginaryPDF::class, Preview\ImaginaryPDF::supportedMimeTypes());
333
-
334
-		// SVG and Bitmap require imagick
335
-		if ($this->imagickSupport->hasExtension()) {
336
-			$imagickProviders = [
337
-				'SVG' => ['mimetype' => '/image\/svg\+xml/', 'class' => Preview\SVG::class],
338
-				'TIFF' => ['mimetype' => '/image\/tiff/', 'class' => Preview\TIFF::class],
339
-				'PDF' => ['mimetype' => '/application\/pdf/', 'class' => Preview\PDF::class],
340
-				'AI' => ['mimetype' => '/application\/illustrator/', 'class' => Preview\Illustrator::class],
341
-				'PSD' => ['mimetype' => '/application\/x-photoshop/', 'class' => Preview\Photoshop::class],
342
-				'EPS' => ['mimetype' => '/application\/postscript/', 'class' => Preview\Postscript::class],
343
-				'TTF' => ['mimetype' => '/application\/(?:font-sfnt|x-font$)/', 'class' => Preview\Font::class],
344
-				'HEIC' => ['mimetype' => '/image\/(x-)?hei(f|c)/', 'class' => Preview\HEIC::class],
345
-				'TGA' => ['mimetype' => '/image\/(x-)?t(ar)?ga/', 'class' => Preview\TGA::class],
346
-				'SGI' => ['mimetype' => '/image\/(x-)?sgi/', 'class' => Preview\SGI::class],
347
-			];
348
-
349
-			foreach ($imagickProviders as $queryFormat => $provider) {
350
-				$class = $provider['class'];
351
-				if (!in_array(trim($class, '\\'), $this->getEnabledDefaultProvider())) {
352
-					continue;
353
-				}
354
-
355
-				if ($this->imagickSupport->supportsFormat($queryFormat)) {
356
-					$this->registerCoreProvider($class, $provider['mimetype']);
357
-				}
358
-			}
359
-		}
360
-
361
-		$this->registerCoreProvidersOffice();
362
-
363
-		// Video requires ffmpeg
364
-		if (in_array(Preview\Movie::class, $this->getEnabledDefaultProvider())) {
365
-			$movieBinary = $this->config->getSystemValue('preview_ffmpeg_path', null);
366
-			if (!is_string($movieBinary)) {
367
-				$movieBinary = $this->binaryFinder->findBinaryPath('ffmpeg');
368
-			}
369
-
370
-
371
-			if (is_string($movieBinary)) {
372
-				$this->registerCoreProvider(Preview\Movie::class, '/video\/.*/', ['movieBinary' => $movieBinary]);
373
-			}
374
-		}
375
-	}
376
-
377
-	private function registerCoreProvidersOffice(): void {
378
-		$officeProviders = [
379
-			['mimetype' => '/application\/msword/', 'class' => Preview\MSOfficeDoc::class],
380
-			['mimetype' => '/application\/vnd.ms-.*/', 'class' => Preview\MSOffice2003::class],
381
-			['mimetype' => '/application\/vnd.openxmlformats-officedocument.*/', 'class' => Preview\MSOffice2007::class],
382
-			['mimetype' => '/application\/vnd.oasis.opendocument.*/', 'class' => Preview\OpenDocument::class],
383
-			['mimetype' => '/application\/vnd.sun.xml.*/', 'class' => Preview\StarOffice::class],
384
-			['mimetype' => '/image\/emf/', 'class' => Preview\EMF::class],
385
-		];
386
-
387
-		$findBinary = true;
388
-		$officeBinary = false;
389
-
390
-		foreach ($officeProviders as $provider) {
391
-			$class = $provider['class'];
392
-			if (!in_array(trim($class, '\\'), $this->getEnabledDefaultProvider())) {
393
-				continue;
394
-			}
395
-
396
-			if ($findBinary) {
397
-				// Office requires openoffice or libreoffice
398
-				$officeBinary = $this->config->getSystemValue('preview_libreoffice_path', false);
399
-				if ($officeBinary === false) {
400
-					$officeBinary = $this->binaryFinder->findBinaryPath('libreoffice');
401
-				}
402
-				if ($officeBinary === false) {
403
-					$officeBinary = $this->binaryFinder->findBinaryPath('openoffice');
404
-				}
405
-				$findBinary = false;
406
-			}
407
-
408
-			if ($officeBinary) {
409
-				$this->registerCoreProvider($class, $provider['mimetype'], ['officeBinary' => $officeBinary]);
410
-			}
411
-		}
412
-	}
413
-
414
-	private function registerBootstrapProviders(): void {
415
-		$context = $this->bootstrapCoordinator->getRegistrationContext();
416
-
417
-		if ($context === null) {
418
-			// Just ignore for now
419
-			return;
420
-		}
421
-
422
-		$providers = $context->getPreviewProviders();
423
-		foreach ($providers as $provider) {
424
-			$key = $provider->getMimeTypeRegex() . '-' . $provider->getService();
425
-			if (array_key_exists($key, $this->loadedBootstrapProviders)) {
426
-				// Do not load the provider more than once
427
-				continue;
428
-			}
429
-			$this->loadedBootstrapProviders[$key] = null;
430
-
431
-			$this->registerProvider($provider->getMimeTypeRegex(), function () use ($provider): IProviderV2|false {
432
-				try {
433
-					return $this->container->get($provider->getService());
434
-				} catch (NotFoundExceptionInterface) {
435
-					return false;
436
-				}
437
-			});
438
-		}
439
-	}
440
-
441
-	/**
442
-	 * @throws NotFoundException if preview generation is disabled
443
-	 */
444
-	private function throwIfPreviewsDisabled(File $file, ?string $mimeType = null): void {
445
-		if (!$this->isAvailable($file, $mimeType)) {
446
-			throw new NotFoundException('Previews disabled');
447
-		}
448
-	}
36
+    protected IConfig $config;
37
+    protected IRootFolder $rootFolder;
38
+    protected IEventDispatcher $eventDispatcher;
39
+    private ?Generator $generator = null;
40
+    private GeneratorHelper $helper;
41
+    protected bool $providerListDirty = false;
42
+    protected bool $registeredCoreProviders = false;
43
+    /**
44
+     * @var array<string, list<ProviderClosure>> $providers
45
+     */
46
+    protected array $providers = [];
47
+
48
+    /** @var array mime type => support status */
49
+    protected array $mimeTypeSupportMap = [];
50
+    /** @var ?list<class-string<IProviderV2>> $defaultProviders */
51
+    protected ?array $defaultProviders = null;
52
+    protected ?string $userId;
53
+    private Coordinator $bootstrapCoordinator;
54
+
55
+    /**
56
+     * Hash map (without value) of loaded bootstrap providers
57
+     * @psalm-var array<string, null>
58
+     */
59
+    private array $loadedBootstrapProviders = [];
60
+    private ContainerInterface $container;
61
+    private IBinaryFinder $binaryFinder;
62
+    private IMagickSupport $imagickSupport;
63
+    private bool $enablePreviews;
64
+
65
+    public function __construct(
66
+        IConfig $config,
67
+        IRootFolder $rootFolder,
68
+        IEventDispatcher $eventDispatcher,
69
+        GeneratorHelper $helper,
70
+        ?string $userId,
71
+        Coordinator $bootstrapCoordinator,
72
+        ContainerInterface $container,
73
+        IBinaryFinder $binaryFinder,
74
+        IMagickSupport $imagickSupport,
75
+    ) {
76
+        $this->config = $config;
77
+        $this->rootFolder = $rootFolder;
78
+        $this->eventDispatcher = $eventDispatcher;
79
+        $this->helper = $helper;
80
+        $this->userId = $userId;
81
+        $this->bootstrapCoordinator = $bootstrapCoordinator;
82
+        $this->container = $container;
83
+        $this->binaryFinder = $binaryFinder;
84
+        $this->imagickSupport = $imagickSupport;
85
+        $this->enablePreviews = $config->getSystemValueBool('enable_previews', true);
86
+    }
87
+
88
+    /**
89
+     * In order to improve lazy loading a closure can be registered which will be
90
+     * called in case preview providers are actually requested
91
+     *
92
+     * @param string $mimeTypeRegex Regex with the mime types that are supported by this provider
93
+     * @param ProviderClosure $callable
94
+     */
95
+    public function registerProvider(string $mimeTypeRegex, Closure $callable): void {
96
+        if (!$this->enablePreviews) {
97
+            return;
98
+        }
99
+
100
+        if (!isset($this->providers[$mimeTypeRegex])) {
101
+            $this->providers[$mimeTypeRegex] = [];
102
+        }
103
+        $this->providers[$mimeTypeRegex][] = $callable;
104
+        $this->providerListDirty = true;
105
+    }
106
+
107
+    /**
108
+     * Get all providers
109
+     */
110
+    public function getProviders(): array {
111
+        if (!$this->enablePreviews) {
112
+            return [];
113
+        }
114
+
115
+        $this->registerCoreProviders();
116
+        $this->registerBootstrapProviders();
117
+        if ($this->providerListDirty) {
118
+            $keys = array_map('strlen', array_keys($this->providers));
119
+            array_multisort($keys, SORT_DESC, $this->providers);
120
+            $this->providerListDirty = false;
121
+        }
122
+
123
+        return $this->providers;
124
+    }
125
+
126
+    /**
127
+     * Does the manager have any providers
128
+     */
129
+    public function hasProviders(): bool {
130
+        $this->registerCoreProviders();
131
+        return !empty($this->providers);
132
+    }
133
+
134
+    private function getGenerator(): Generator {
135
+        if ($this->generator === null) {
136
+            $this->generator = new Generator(
137
+                $this->config,
138
+                $this,
139
+                new GeneratorHelper(),
140
+                $this->eventDispatcher,
141
+                $this->container->get(LoggerInterface::class),
142
+                $this->container->get(PreviewMapper::class),
143
+                $this->container->get(StorageFactory::class),
144
+            );
145
+        }
146
+        return $this->generator;
147
+    }
148
+
149
+    public function getPreview(
150
+        File $file,
151
+        int $width = -1,
152
+        int $height = -1,
153
+        bool $crop = false,
154
+        string $mode = IPreview::MODE_FILL,
155
+        ?string $mimeType = null,
156
+        bool $cacheResult = true,
157
+    ): ISimpleFile {
158
+        $this->throwIfPreviewsDisabled($file, $mimeType);
159
+        $previewConcurrency = $this->getGenerator()->getNumConcurrentPreviews('preview_concurrency_all');
160
+        $sem = Generator::guardWithSemaphore(Generator::SEMAPHORE_ID_ALL, $previewConcurrency);
161
+        try {
162
+            $preview = $this->getGenerator()->getPreview($file, $width, $height, $crop, $mode, $mimeType, $cacheResult);
163
+        } finally {
164
+            Generator::unguardWithSemaphore($sem);
165
+        }
166
+
167
+        return $preview;
168
+    }
169
+
170
+    /**
171
+     * Generates previews of a file
172
+     *
173
+     * @param array $specifications
174
+     * @return ISimpleFile the last preview that was generated
175
+     * @throws NotFoundException
176
+     * @throws \InvalidArgumentException if the preview would be invalid (in case the original image is invalid)
177
+     * @since 19.0.0
178
+     */
179
+    public function generatePreviews(File $file, array $specifications, ?string $mimeType = null): ISimpleFile {
180
+        $this->throwIfPreviewsDisabled($file, $mimeType);
181
+        return $this->getGenerator()->generatePreviews($file, $specifications, $mimeType);
182
+    }
183
+
184
+    public function isMimeSupported(string $mimeType = '*'): bool {
185
+        if (!$this->enablePreviews) {
186
+            return false;
187
+        }
188
+
189
+        if (isset($this->mimeTypeSupportMap[$mimeType])) {
190
+            return $this->mimeTypeSupportMap[$mimeType];
191
+        }
192
+
193
+        $this->registerCoreProviders();
194
+        $this->registerBootstrapProviders();
195
+        $providerMimeTypes = array_keys($this->providers);
196
+        foreach ($providerMimeTypes as $supportedMimeType) {
197
+            if (preg_match($supportedMimeType, $mimeType)) {
198
+                $this->mimeTypeSupportMap[$mimeType] = true;
199
+                return true;
200
+            }
201
+        }
202
+        $this->mimeTypeSupportMap[$mimeType] = false;
203
+        return false;
204
+    }
205
+
206
+    public function isAvailable(\OCP\Files\FileInfo $file, ?string $mimeType = null): bool {
207
+        if (!$this->enablePreviews) {
208
+            return false;
209
+        }
210
+
211
+        $fileMimeType = $mimeType ?? $file->getMimeType();
212
+
213
+        $this->registerCoreProviders();
214
+        if (!$this->isMimeSupported($fileMimeType)) {
215
+            return false;
216
+        }
217
+
218
+        $mount = $file->getMountPoint();
219
+        if ($mount && !$mount->getOption('previews', true)) {
220
+            return false;
221
+        }
222
+
223
+        foreach ($this->providers as $supportedMimeType => $providers) {
224
+            if (preg_match($supportedMimeType, $fileMimeType)) {
225
+                foreach ($providers as $providerClosure) {
226
+                    $provider = $this->helper->getProvider($providerClosure);
227
+                    if (!$provider) {
228
+                        continue;
229
+                    }
230
+                    if ($provider->isAvailable($file)) {
231
+                        return true;
232
+                    }
233
+                }
234
+            }
235
+        }
236
+        return false;
237
+    }
238
+
239
+    /**
240
+     * List of enabled default providers
241
+     *
242
+     * The following providers are enabled by default:
243
+     *  - OC\Preview\BMP
244
+     *  - OC\Preview\GIF
245
+     *  - OC\Preview\JPEG
246
+     *  - OC\Preview\MarkDown
247
+     *  - OC\Preview\PNG
248
+     *  - OC\Preview\TXT
249
+     *  - OC\Preview\XBitmap
250
+     *
251
+     * The following providers are disabled by default due to performance or privacy concerns:
252
+     *  - OC\Preview\Font
253
+     *  - OC\Preview\HEIC
254
+     *  - OC\Preview\Illustrator
255
+     *  - OC\Preview\MP3
256
+     *  - OC\Preview\MSOffice2003
257
+     *  - OC\Preview\MSOffice2007
258
+     *  - OC\Preview\MSOfficeDoc
259
+     *  - OC\Preview\Movie
260
+     *  - OC\Preview\OpenDocument
261
+     *  - OC\Preview\PDF
262
+     *  - OC\Preview\Photoshop
263
+     *  - OC\Preview\Postscript
264
+     *  - OC\Preview\SVG
265
+     *  - OC\Preview\StarOffice
266
+     *  - OC\Preview\TIFF
267
+     *
268
+     * @return list<class-string<IProviderV2>>
269
+     */
270
+    protected function getEnabledDefaultProvider(): array {
271
+        if ($this->defaultProviders !== null) {
272
+            return $this->defaultProviders;
273
+        }
274
+
275
+        $imageProviders = [
276
+            Preview\PNG::class,
277
+            Preview\JPEG::class,
278
+            Preview\GIF::class,
279
+            Preview\BMP::class,
280
+            Preview\XBitmap::class,
281
+            Preview\Krita::class,
282
+            Preview\WebP::class,
283
+        ];
284
+
285
+        $this->defaultProviders = $this->config->getSystemValue('enabledPreviewProviders', array_merge([
286
+            Preview\MarkDown::class,
287
+            Preview\TXT::class,
288
+            Preview\OpenDocument::class,
289
+        ], $imageProviders));
290
+
291
+        if (in_array(Preview\Image::class, $this->defaultProviders)) {
292
+            $this->defaultProviders = array_merge($this->defaultProviders, $imageProviders);
293
+        }
294
+        $this->defaultProviders = array_values(array_unique($this->defaultProviders));
295
+        /** @var list<class-string<IProviderV2>> $providers */
296
+        $providers = $this->defaultProviders;
297
+        return $providers;
298
+    }
299
+
300
+    /**
301
+     * Register the default providers (if enabled)
302
+     */
303
+    protected function registerCoreProvider(string $class, string $mimeType, array $options = []): void {
304
+        if (in_array(trim($class, '\\'), $this->getEnabledDefaultProvider())) {
305
+            $this->registerProvider($mimeType, function () use ($class, $options) {
306
+                return new $class($options);
307
+            });
308
+        }
309
+    }
310
+
311
+    /**
312
+     * Register the default providers (if enabled)
313
+     */
314
+    protected function registerCoreProviders(): void {
315
+        if ($this->registeredCoreProviders) {
316
+            return;
317
+        }
318
+        $this->registeredCoreProviders = true;
319
+
320
+        $this->registerCoreProvider(Preview\TXT::class, '/text\/plain/');
321
+        $this->registerCoreProvider(Preview\MarkDown::class, '/text\/(x-)?markdown/');
322
+        $this->registerCoreProvider(Preview\PNG::class, '/image\/png/');
323
+        $this->registerCoreProvider(Preview\JPEG::class, '/image\/jpeg/');
324
+        $this->registerCoreProvider(Preview\GIF::class, '/image\/gif/');
325
+        $this->registerCoreProvider(Preview\BMP::class, '/image\/bmp/');
326
+        $this->registerCoreProvider(Preview\XBitmap::class, '/image\/x-xbitmap/');
327
+        $this->registerCoreProvider(Preview\WebP::class, '/image\/webp/');
328
+        $this->registerCoreProvider(Preview\Krita::class, '/application\/x-krita/');
329
+        $this->registerCoreProvider(Preview\MP3::class, '/audio\/mpeg$/');
330
+        $this->registerCoreProvider(Preview\OpenDocument::class, '/application\/vnd.oasis.opendocument.*/');
331
+        $this->registerCoreProvider(Preview\Imaginary::class, Preview\Imaginary::supportedMimeTypes());
332
+        $this->registerCoreProvider(Preview\ImaginaryPDF::class, Preview\ImaginaryPDF::supportedMimeTypes());
333
+
334
+        // SVG and Bitmap require imagick
335
+        if ($this->imagickSupport->hasExtension()) {
336
+            $imagickProviders = [
337
+                'SVG' => ['mimetype' => '/image\/svg\+xml/', 'class' => Preview\SVG::class],
338
+                'TIFF' => ['mimetype' => '/image\/tiff/', 'class' => Preview\TIFF::class],
339
+                'PDF' => ['mimetype' => '/application\/pdf/', 'class' => Preview\PDF::class],
340
+                'AI' => ['mimetype' => '/application\/illustrator/', 'class' => Preview\Illustrator::class],
341
+                'PSD' => ['mimetype' => '/application\/x-photoshop/', 'class' => Preview\Photoshop::class],
342
+                'EPS' => ['mimetype' => '/application\/postscript/', 'class' => Preview\Postscript::class],
343
+                'TTF' => ['mimetype' => '/application\/(?:font-sfnt|x-font$)/', 'class' => Preview\Font::class],
344
+                'HEIC' => ['mimetype' => '/image\/(x-)?hei(f|c)/', 'class' => Preview\HEIC::class],
345
+                'TGA' => ['mimetype' => '/image\/(x-)?t(ar)?ga/', 'class' => Preview\TGA::class],
346
+                'SGI' => ['mimetype' => '/image\/(x-)?sgi/', 'class' => Preview\SGI::class],
347
+            ];
348
+
349
+            foreach ($imagickProviders as $queryFormat => $provider) {
350
+                $class = $provider['class'];
351
+                if (!in_array(trim($class, '\\'), $this->getEnabledDefaultProvider())) {
352
+                    continue;
353
+                }
354
+
355
+                if ($this->imagickSupport->supportsFormat($queryFormat)) {
356
+                    $this->registerCoreProvider($class, $provider['mimetype']);
357
+                }
358
+            }
359
+        }
360
+
361
+        $this->registerCoreProvidersOffice();
362
+
363
+        // Video requires ffmpeg
364
+        if (in_array(Preview\Movie::class, $this->getEnabledDefaultProvider())) {
365
+            $movieBinary = $this->config->getSystemValue('preview_ffmpeg_path', null);
366
+            if (!is_string($movieBinary)) {
367
+                $movieBinary = $this->binaryFinder->findBinaryPath('ffmpeg');
368
+            }
369
+
370
+
371
+            if (is_string($movieBinary)) {
372
+                $this->registerCoreProvider(Preview\Movie::class, '/video\/.*/', ['movieBinary' => $movieBinary]);
373
+            }
374
+        }
375
+    }
376
+
377
+    private function registerCoreProvidersOffice(): void {
378
+        $officeProviders = [
379
+            ['mimetype' => '/application\/msword/', 'class' => Preview\MSOfficeDoc::class],
380
+            ['mimetype' => '/application\/vnd.ms-.*/', 'class' => Preview\MSOffice2003::class],
381
+            ['mimetype' => '/application\/vnd.openxmlformats-officedocument.*/', 'class' => Preview\MSOffice2007::class],
382
+            ['mimetype' => '/application\/vnd.oasis.opendocument.*/', 'class' => Preview\OpenDocument::class],
383
+            ['mimetype' => '/application\/vnd.sun.xml.*/', 'class' => Preview\StarOffice::class],
384
+            ['mimetype' => '/image\/emf/', 'class' => Preview\EMF::class],
385
+        ];
386
+
387
+        $findBinary = true;
388
+        $officeBinary = false;
389
+
390
+        foreach ($officeProviders as $provider) {
391
+            $class = $provider['class'];
392
+            if (!in_array(trim($class, '\\'), $this->getEnabledDefaultProvider())) {
393
+                continue;
394
+            }
395
+
396
+            if ($findBinary) {
397
+                // Office requires openoffice or libreoffice
398
+                $officeBinary = $this->config->getSystemValue('preview_libreoffice_path', false);
399
+                if ($officeBinary === false) {
400
+                    $officeBinary = $this->binaryFinder->findBinaryPath('libreoffice');
401
+                }
402
+                if ($officeBinary === false) {
403
+                    $officeBinary = $this->binaryFinder->findBinaryPath('openoffice');
404
+                }
405
+                $findBinary = false;
406
+            }
407
+
408
+            if ($officeBinary) {
409
+                $this->registerCoreProvider($class, $provider['mimetype'], ['officeBinary' => $officeBinary]);
410
+            }
411
+        }
412
+    }
413
+
414
+    private function registerBootstrapProviders(): void {
415
+        $context = $this->bootstrapCoordinator->getRegistrationContext();
416
+
417
+        if ($context === null) {
418
+            // Just ignore for now
419
+            return;
420
+        }
421
+
422
+        $providers = $context->getPreviewProviders();
423
+        foreach ($providers as $provider) {
424
+            $key = $provider->getMimeTypeRegex() . '-' . $provider->getService();
425
+            if (array_key_exists($key, $this->loadedBootstrapProviders)) {
426
+                // Do not load the provider more than once
427
+                continue;
428
+            }
429
+            $this->loadedBootstrapProviders[$key] = null;
430
+
431
+            $this->registerProvider($provider->getMimeTypeRegex(), function () use ($provider): IProviderV2|false {
432
+                try {
433
+                    return $this->container->get($provider->getService());
434
+                } catch (NotFoundExceptionInterface) {
435
+                    return false;
436
+                }
437
+            });
438
+        }
439
+    }
440
+
441
+    /**
442
+     * @throws NotFoundException if preview generation is disabled
443
+     */
444
+    private function throwIfPreviewsDisabled(File $file, ?string $mimeType = null): void {
445
+        if (!$this->isAvailable($file, $mimeType)) {
446
+            throw new NotFoundException('Previews disabled');
447
+        }
448
+    }
449 449
 }
Please login to merge, or discard this patch.