Passed
Push — master ( 9f6f8b...b68386 )
by Pauli
03:11 queued 16s
created

ApiController::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 33
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 16
c 0
b 0
f 0
nc 1
nop 17
dl 0
loc 33
ccs 0
cts 17
cp 0
crap 2
rs 9.7333

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
/**
4
 * ownCloud - Music app
5
 *
6
 * This file is licensed under the Affero General Public License version 3 or
7
 * later. See the COPYING file.
8
 *
9
 * @author Morris Jobke <[email protected]>
10
 * @author Pauli Järvinen <[email protected]>
11
 * @copyright Morris Jobke 2013, 2014
12
 * @copyright Pauli Järvinen 2017 - 2020
13
 */
14
15
namespace OCA\Music\Controller;
16
17
use \OCP\AppFramework\Controller;
0 ignored issues
show
Bug introduced by
The type OCP\AppFramework\Controller was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
18
use \OCP\AppFramework\Http;
0 ignored issues
show
Bug introduced by
The type OCP\AppFramework\Http was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
19
use \OCP\AppFramework\Http\DataDisplayResponse;
0 ignored issues
show
Bug introduced by
The type OCP\AppFramework\Http\DataDisplayResponse was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
20
use \OCP\AppFramework\Http\JSONResponse;
0 ignored issues
show
Bug introduced by
The type OCP\AppFramework\Http\JSONResponse was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
21
use \OCP\AppFramework\Http\RedirectResponse;
0 ignored issues
show
Bug introduced by
The type OCP\AppFramework\Http\RedirectResponse was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
22
use \OCP\Files\Folder;
0 ignored issues
show
Bug introduced by
The type OCP\Files\Folder was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
23
use \OCP\IL10N;
0 ignored issues
show
Bug introduced by
The type OCP\IL10N was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
24
use \OCP\IRequest;
0 ignored issues
show
Bug introduced by
The type OCP\IRequest was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
25
use \OCP\IURLGenerator;
0 ignored issues
show
Bug introduced by
The type OCP\IURLGenerator was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
26
27
use \OCA\Music\AppFramework\BusinessLayer\BusinessLayerException;
28
use \OCA\Music\AppFramework\Core\Logger;
29
use \OCA\Music\BusinessLayer\AlbumBusinessLayer;
30
use \OCA\Music\BusinessLayer\ArtistBusinessLayer;
31
use \OCA\Music\BusinessLayer\GenreBusinessLayer;
32
use \OCA\Music\BusinessLayer\TrackBusinessLayer;
33
use \OCA\Music\Db\Album;
34
use \OCA\Music\Db\Artist;
35
use \OCA\Music\Db\Maintenance;
36
use \OCA\Music\Db\Track;
37
use \OCA\Music\Http\ErrorResponse;
38
use \OCA\Music\Http\FileResponse;
39
use \OCA\Music\Utility\CollectionHelper;
40
use \OCA\Music\Utility\CoverHelper;
41
use \OCA\Music\Utility\DetailsHelper;
42
use \OCA\Music\Utility\LastfmService;
43
use \OCA\Music\Utility\Scanner;
44
45
class ApiController extends Controller {
46
47
	/** @var IL10N */
48
	private $l10n;
49
	/** @var TrackBusinessLayer */
50
	private $trackBusinessLayer;
51
	/** @var ArtistBusinessLayer */
52
	private $artistBusinessLayer;
53
	/** @var AlbumBusinessLayer */
54
	private $albumBusinessLayer;
55
	/** @var GenreBusinessLayer */
56
	private $genreBusinessLayer;
57
	/** @var Scanner */
58
	private $scanner;
59
	/** @var CollectionHelper */
60
	private $collectionHelper;
61
	/** @var CoverHelper */
62
	private $coverHelper;
63
	/** @var DetailsHelper */
64
	private $detailsHelper;
65
	/** @var LastfmService */
66
	private $lastfmService;
67
	/** @var Maintenance */
68
	private $maintenance;
69
	/** @var string */
70
	private $userId;
71
	/** @var IURLGenerator */
72
	private $urlGenerator;
73
	/** @var Folder */
74
	private $userFolder;
75
	/** @var Logger */
76
	private $logger;
77
78
	public function __construct($appname,
79
								IRequest $request,
80
								IURLGenerator $urlGenerator,
81
								TrackBusinessLayer $trackbusinesslayer,
82
								ArtistBusinessLayer $artistbusinesslayer,
83
								AlbumBusinessLayer $albumbusinesslayer,
84
								GenreBusinessLayer $genreBusinessLayer,
85
								Scanner $scanner,
86
								CollectionHelper $collectionHelper,
87
								CoverHelper $coverHelper,
88
								DetailsHelper $detailsHelper,
89
								LastfmService $lastfmService,
90
								Maintenance $maintenance,
91
								$userId,
92
								IL10N $l10n,
93
								/*Folder*/ $userFolder, // no type-hint as this may sometimes be null
94
								Logger $logger) {
95
		parent::__construct($appname, $request);
96
		$this->l10n = $l10n;
97
		$this->trackBusinessLayer = $trackbusinesslayer;
98
		$this->artistBusinessLayer = $artistbusinesslayer;
99
		$this->albumBusinessLayer = $albumbusinesslayer;
100
		$this->genreBusinessLayer = $genreBusinessLayer;
101
		$this->scanner = $scanner;
102
		$this->collectionHelper = $collectionHelper;
103
		$this->coverHelper = $coverHelper;
104
		$this->detailsHelper = $detailsHelper;
105
		$this->lastfmService = $lastfmService;
106
		$this->maintenance = $maintenance;
107
		$this->userId = $userId;
108
		$this->urlGenerator = $urlGenerator;
109
		$this->userFolder = $userFolder;
110
		$this->logger = $logger;
111
	}
112
113
	/**
114
	 * Extracts the id from an unique slug (id-slug)
115
	 * @param string $slug the slug
116
	 * @return integer the id
117
	 */
118
	protected static function getIdFromSlug($slug) {
119
		$split = \explode('-', $slug, 2);
120
121
		return (int)$split[0];
122
	}
123
124
	/**
125
	 * @NoAdminRequired
126
	 * @NoCSRFRequired
127
	 */
128
	public function prepareCollection() {
129
		$hash = $this->collectionHelper->getCachedJsonHash();
130
		if ($hash === null) {
131
			// build the collection but ignore the data for now
132
			$this->collectionHelper->getJson();
133
			$hash = $this->collectionHelper->getCachedJsonHash();
134
		}
135
		return new JSONResponse(['hash' => $hash]);
136
	}
137
138
	/**
139
	 * @NoAdminRequired
140
	 * @NoCSRFRequired
141
	 */
142
	public function collection() {
143
144
		$collectionJson = $this->collectionHelper->getJson();
145
		$response = new DataDisplayResponse($collectionJson);
146
		$response->addHeader('Content-Type', 'application/json; charset=utf-8');
147
148
		// Instruct the client to cache the result in case it requested the collection with
149
		// the correct hash. The hash could be incorrect if the collection would have changed
150
		// between calls to prepareCollection() and colletion().
151
		$requestHash = $this->request->getParam('hash');
152
		$actualHash = $this->collectionHelper->getCachedJsonHash();
153
		if (!empty($actualHash) && $requestHash === $actualHash) {
154
			self::setClientCaching($response, 90); // cache for 3 months
155
		}
156
157
		return $response;
158
	}
159
160
	/**
161
	 * @NoAdminRequired
162
	 * @NoCSRFRequired
163
	 */
164
	public function folders() {
165
		$folders = $this->trackBusinessLayer->findAllFolders($this->userId, $this->userFolder);
166
		return new JSONResponse($folders);
167
	}
168
169
	/**
170
	 * @NoAdminRequired
171
	 * @NoCSRFRequired
172
	 */
173
	public function genres() {
174
		$genres = $this->genreBusinessLayer->findAllWithTrackIds($this->userId);
175
		$unscanned =  $this->trackBusinessLayer->findFilesWithoutScannedGenre($this->userId);
176
		return new JSONResponse([
177
			'genres' => \array_map(function($g) {return $g->toApi();}, $genres),
178
			'unscanned' => $unscanned
179
		]);
180
	}
181
182
	/**
183
	 * @NoAdminRequired
184
	 * @NoCSRFRequired
185
	 */
186
	public function artists($fulltree, $albums) {
187
		$fulltree = \filter_var($fulltree, FILTER_VALIDATE_BOOLEAN);
188
		$includeAlbums = \filter_var($albums, FILTER_VALIDATE_BOOLEAN);
189
		/** @var Artist[] $artists */
190
		$artists = $this->artistBusinessLayer->findAll($this->userId);
191
192
		$artists = \array_map(function($a) use ($fulltree, $includeAlbums) {
193
			return $this->artistToApi($a, $includeAlbums || $fulltree, $fulltree);
194
		}, $artists);
195
196
		return new JSONResponse($artists);
197
	}
198
199
	/**
200
	 * @NoAdminRequired
201
	 * @NoCSRFRequired
202
	 */
203
	public function artist($artistIdOrSlug, $fulltree) {
204
		$fulltree = \filter_var($fulltree, FILTER_VALIDATE_BOOLEAN);
205
		$artistId = $this->getIdFromSlug($artistIdOrSlug);
206
		/** @var Artist $artist */
207
		$artist = $this->artistBusinessLayer->find($artistId, $this->userId);
208
		$artist = $this->artistToApi($artist, $fulltree, $fulltree);
209
		return new JSONResponse($artist);
210
	}
211
212
	/**
213
	 * Return given artist in Shia API format
214
	 * @param Artist $artist
215
	 * @param boolean $includeAlbums
216
	 * @param boolean $includeTracks (ignored if $includeAlbums==false)
217
	 * @return array
218
	 */
219
	private function artistToApi($artist, $includeAlbums, $includeTracks) {
220
		$artistInApi = $artist->toAPI($this->urlGenerator, $this->l10n);
221
		if ($includeAlbums) {
222
			$artistId = $artist->getId();
223
			$albums = $this->albumBusinessLayer->findAllByArtist($artistId, $this->userId);
224
225
			$artistInApi['albums'] = \array_map(function($a) use ($includeTracks) {
226
				return $this->albumToApi($a, $includeTracks, false);
227
			}, $albums);
228
		}
229
		return $artistInApi;
230
	}
231
232
	/**
233
	 * @NoAdminRequired
234
	 * @NoCSRFRequired
235
	 */
236
	public function albums($artist, $fulltree) {
237
		$fulltree = \filter_var($fulltree, FILTER_VALIDATE_BOOLEAN);
238
		if ($artist) {
239
			$albums = $this->albumBusinessLayer->findAllByArtist($artist, $this->userId);
240
		} else {
241
			$albums = $this->albumBusinessLayer->findAll($this->userId);
242
		}
243
244
		$albums = \array_map(function($a) use ($fulltree) {
245
			return $this->albumToApi($a, $fulltree, $fulltree);
246
		}, $albums);
247
248
		return new JSONResponse($albums);
249
	}
250
251
	/**
252
	 * @NoAdminRequired
253
	 * @NoCSRFRequired
254
	 */
255
	public function album($albumIdOrSlug, $fulltree) {
256
		$fulltree = \filter_var($fulltree, FILTER_VALIDATE_BOOLEAN);
257
		$albumId = $this->getIdFromSlug($albumIdOrSlug);
258
		$album = $this->albumBusinessLayer->find($albumId, $this->userId);
259
		$album = $this->albumToApi($album, $fulltree, $fulltree);
260
		return new JSONResponse($album);
261
	}
262
263
	/**
264
	 * Return given album in the Shiva API format
265
	 * @param Album $album
266
	 * @param boolean $includeTracks
267
	 * @param boolean $includeAlbums
268
	 * @return array
269
	 */
270
	private function albumToApi($album, $includeTracks, $includeArtists) {
271
		$albumInApi = $album->toAPI($this->urlGenerator, $this->l10n);
272
273
		if ($includeTracks) {
274
			$albumId = $album->getId();
275
			$tracks = $this->trackBusinessLayer->findAllByAlbum($albumId, $this->userId);
276
			$albumInApi['tracks'] = \array_map(function($t) {
277
				return $t->toAPI($this->urlGenerator);
278
			}, $tracks);
279
		}
280
281
		if ($includeArtists) {
282
			$artistIds = $album->getArtistIds();
283
			$artists = $this->artistBusinessLayer->findById($artistIds, $this->userId);
284
			$albumInApi['artists'] = \array_map(function($a) {
285
				return $a->toAPI($this->urlGenerator, $this->l10n);
286
			}, $artists);
287
		}
288
289
		return $albumInApi;
290
	}
291
292
	/**
293
	 * @NoAdminRequired
294
	 * @NoCSRFRequired
295
	 */
296
	public function tracks($artist, $album, $fulltree) {
297
		$fulltree = \filter_var($fulltree, FILTER_VALIDATE_BOOLEAN);
298
		if ($artist) {
299
			$tracks = $this->trackBusinessLayer->findAllByArtist($artist, $this->userId);
300
		} elseif ($album) {
301
			$tracks = $this->trackBusinessLayer->findAllByAlbum($album, $this->userId);
302
		} else {
303
			$tracks = $this->trackBusinessLayer->findAll($this->userId);
304
		}
305
		foreach ($tracks as &$track) {
306
			$artistId = $track->getArtistId();
307
			$albumId = $track->getAlbumId();
308
			$track = $track->toAPI($this->urlGenerator);
309
			if ($fulltree) {
310
				/** @var Artist $artist */
311
				$artist = $this->artistBusinessLayer->find($artistId, $this->userId);
312
				$track['artist'] = $artist->toAPI($this->urlGenerator, $this->l10n);
313
				$album = $this->albumBusinessLayer->find($albumId, $this->userId);
314
				$track['album'] = $album->toAPI($this->urlGenerator, $this->l10n);
315
			}
316
		}
317
		return new JSONResponse($tracks);
318
	}
319
320
	/**
321
	 * @NoAdminRequired
322
	 * @NoCSRFRequired
323
	 */
324
	public function track($trackIdOrSlug) {
325
		$trackId = $this->getIdFromSlug($trackIdOrSlug);
326
		/** @var Track $track */
327
		$track = $this->trackBusinessLayer->find($trackId, $this->userId);
328
		return new JSONResponse($track->toAPI($this->urlGenerator));
329
	}
330
331
	/**
332
	 * @NoAdminRequired
333
	 * @NoCSRFRequired
334
	 */
335
	public function trackByFileId($fileId) {
336
		$track = $this->trackBusinessLayer->findByFileId($fileId, $this->userId);
337
		if ($track !== null) {
338
			$track->setAlbum($this->albumBusinessLayer->find($track->getAlbumId(), $this->userId));
339
			$track->setArtist($this->artistBusinessLayer->find($track->getArtistId(), $this->userId));
340
			return new JSONResponse($track->toCollection($this->l10n));
341
		} else {
342
			return new ErrorResponse(Http::STATUS_NOT_FOUND);
343
		}
344
	}
345
346
	/**
347
	 * @NoAdminRequired
348
	 * @NoCSRFRequired
349
	 */
350
	public function getScanState() {
351
		return new JSONResponse([
352
			'unscannedFiles' => $this->scanner->getUnscannedMusicFileIds($this->userId),
353
			'scannedCount' => $this->trackBusinessLayer->count($this->userId)
354
		]);
355
	}
356
357
	/**
358
	 * @NoAdminRequired
359
	 * @UseSession to keep the session reserved while execution in progress
360
	 */
361
	public function scan($files, $finalize) {
362
		// extract the parameters
363
		$fileIds = \array_map('intval', \explode(',', $files));
364
		$finalize = \filter_var($finalize, FILTER_VALIDATE_BOOLEAN);
365
366
		$filesScanned = $this->scanner->scanFiles($this->userId, $this->userFolder, $fileIds);
367
368
		$coversUpdated = false;
369
		if ($finalize) {
370
			$coversUpdated = $this->scanner->findAlbumCovers($this->userId)
371
							|| $this->scanner->findArtistCovers($this->userId);
372
			$totalCount = $this->trackBusinessLayer->count($this->userId);
373
			$this->logger->log("Scanning finished, user $this->userId has $totalCount scanned tracks in total", 'info');
374
		}
375
376
		return new JSONResponse([
377
			'filesScanned' => $filesScanned,
378
			'coversUpdated' => $coversUpdated
379
		]);
380
	}
381
382
	/**
383
	 * @NoAdminRequired
384
	 * @UseSession to keep the session reserved while execution in progress
385
	 */
386
	public function resetScanned() {
387
		$this->maintenance->resetDb($this->userId);
388
		return new JSONResponse(['success' => true]);
389
	}
390
391
	/**
392
	 * @NoAdminRequired
393
	 * @NoCSRFRequired
394
	 */
395
	public function download($fileId) {
396
		$track = $this->trackBusinessLayer->findByFileId($fileId, $this->userId);
397
		if ($track === null) {
398
			return new ErrorResponse(Http::STATUS_NOT_FOUND, 'track not found');
399
		}
400
401
		$nodes = $this->userFolder->getById($track->getFileId());
402
		if (\count($nodes) > 0) {
403
			// get the first valid node
404
			$node = $nodes[0];
405
406
			$mime = $node->getMimeType();
407
			$content = $node->getContent();
408
			return new FileResponse(['mimetype' => $mime, 'content' => $content]);
409
		}
410
411
		return new ErrorResponse(Http::STATUS_NOT_FOUND, 'file not found');
412
	}
413
414
	/**
415
	 * @NoAdminRequired
416
	 * @NoCSRFRequired
417
	 */
418
	public function filePath($fileId) {
419
		$nodes = $this->userFolder->getById($fileId);
420
		if (\count($nodes) == 0) {
421
			return new ErrorResponse(Http::STATUS_NOT_FOUND);
422
		} else {
423
			$node = $nodes[0];
424
			$path = $this->userFolder->getRelativePath($node->getPath());
425
			// URL encode each part of the file path
426
			$path = \join('/', \array_map('rawurlencode', \explode('/', $path)));
427
			return new JSONResponse(['path' => $path]);
428
		}
429
	}
430
431
	/**
432
	 * @NoAdminRequired
433
	 * @NoCSRFRequired
434
	 */
435
	public function fileInfo($fileId) {
436
		$info = $this->scanner->getFileInfo($fileId, $this->userId, $this->userFolder);
437
		if ($info) {
438
			return new JSONResponse($info);
439
		} else {
440
			return new ErrorResponse(Http::STATUS_NOT_FOUND);
441
		}
442
	}
443
444
	/**
445
	 * @NoAdminRequired
446
	 * @NoCSRFRequired
447
	 */
448
	public function fileDetails($fileId) {
449
		$details = $this->detailsHelper->getDetails($fileId, $this->userFolder);
450
		if ($details) {
451
			return new JSONResponse($details);
452
		} else {
453
			return new ErrorResponse(Http::STATUS_NOT_FOUND);
454
		}
455
	}
456
457
	/**
458
	 * @NoAdminRequired
459
	 * @NoCSRFRequired
460
	 */
461
	public function artistDetails($artistIdOrSlug) {
462
		try {
463
			$artistId = $this->getIdFromSlug($artistIdOrSlug);
464
			$info = $this->lastfmService->getArtistInfo($artistId, $this->userId);
465
			return new JSONResponse($info);
466
		}
467
		catch (BusinessLayerException $e) {
468
			return new ErrorResponse(Http::STATUS_NOT_FOUND);
469
		}
470
	}
471
472
	/**
473
	 * @NoAdminRequired
474
	 * @NoCSRFRequired
475
	 */
476
	public function albumCover($albumIdOrSlug) {
477
		$albumId = $this->getIdFromSlug($albumIdOrSlug);
478
		$album = $this->albumBusinessLayer->find($albumId, $this->userId);
479
		return $this->cover($album);
480
	}
481
482
	/**
483
	 * @NoAdminRequired
484
	 * @NoCSRFRequired
485
	 */
486
	public function artistCover($artistIdOrSlug, $originalSize) {
487
		$originalSize = \filter_var($originalSize, FILTER_VALIDATE_BOOLEAN);
488
489
		$artistId = $this->getIdFromSlug($artistIdOrSlug);
490
		$artist = $this->artistBusinessLayer->find($artistId, $this->userId);
491
492
		if ($originalSize) {
493
			$cover = $this->coverHelper->getCover(
494
					$artist, $this->userId, $this->userFolder, CoverHelper::DO_NOT_CROP_OR_SCALE);
495
			if ($cover !== null) {
496
				return new FileResponse($cover);
497
			} else {
498
				return new ErrorResponse(Http::STATUS_NOT_FOUND);
499
			}
500
		}
501
		else {
502
			return $this->cover($artist);
503
		}
504
	}
505
506
	private function cover($entity) {
507
		$coverAndHash = $this->coverHelper->getCoverAndHash($entity, $this->userId, $this->userFolder);
508
509
		if ($coverAndHash['hash'] !== null) {
510
			// Cover is in cache. Return a redirection response so that the client
511
			// will fetch the content through a cacheable route.
512
			$link = $this->urlGenerator->linkToRoute('music.api.cachedCover', ['hash' => $coverAndHash['hash']]);
513
			return new RedirectResponse($link);
514
		} else if ($coverAndHash['data'] !== null) {
515
			return new FileResponse($coverAndHash['data']);
516
		} else {
517
			return new ErrorResponse(Http::STATUS_NOT_FOUND);
518
		}
519
	}
520
521
	/**
522
	 * @NoAdminRequired
523
	 * @NoCSRFRequired
524
	 */
525
	public function cachedCover($hash) {
526
		$coverData = $this->coverHelper->getCoverFromCache($hash, $this->userId);
527
528
		if ($coverData !== null) {
529
			$response =  new FileResponse($coverData);
530
			// instruct also the client-side to cache the result, this is safe
531
			// as the resource URI contains the image hash
532
			self::setClientCaching($response);
533
			return $response;
534
		} else {
535
			return new ErrorResponse(Http::STATUS_NOT_FOUND);
536
		}
537
	}
538
539
	private static function setClientCaching(&$httpResponse, $days=365) {
540
		$httpResponse->cacheFor($days * 24 * 60 * 60);
541
		$httpResponse->addHeader('Pragma', 'cache');
542
	}
543
}
544