Completed
Push — scalability_improvements ( 14d4cf...be3c8d )
by Pauli
13:23
created

ApiController::fileWebDavUrl()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 14
rs 9.4285
cc 2
eloc 9
nc 2
nop 0
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
 * @copyright Morris Jobke 2013, 2014
11
 */
12
13
namespace OCA\Music\Controller;
14
15
use OCA\Music\AppFramework\Core\Logger;
16
use OCA\Music\Db\Artist;
17
use OCA\Music\Db\Cache;
18
use OCA\Music\Db\Track;
19
use \OCP\AppFramework\Controller;
20
use \OCP\AppFramework\Http;
21
use \OCP\AppFramework\Http\DataDisplayResponse;
22
use \OCP\AppFramework\Http\JSONResponse;
23
use \OCP\AppFramework\Http\Response;
24
use \OCP\Files\Folder;
25
use \OCP\IL10N;
26
use \OCP\IRequest;
27
use \OCP\IURLGenerator;
28
29
use \OCP\AppFramework\Db\DoesNotExistException;
30
31
use \OCA\Music\BusinessLayer\TrackBusinessLayer;
32
use \OCA\Music\BusinessLayer\ArtistBusinessLayer;
33
use \OCA\Music\BusinessLayer\AlbumBusinessLayer;
34
use \OCA\Music\Http\FileResponse;
35
use \OCA\Music\Utility\Scanner;
36
37
38
class ApiController extends Controller {
39
40
	/** @var IL10N */
41
	private $l10n;
42
	/** @var TrackBusinessLayer */
43
	private $trackBusinessLayer;
44
	/** @var ArtistBusinessLayer */
45
	private $artistBusinessLayer;
46
	/** @var AlbumBusinessLayer */
47
	private $albumBusinessLayer;
48
	/** @var Cache */
49
	private $cache;
50
	/** @var Scanner */
51
	private $scanner;
52
	/** @var string */
53
	private $userId;
54
	/** @var IURLGenerator */
55
	private $urlGenerator;
56
	/** @var Folder */
57
	private $userFolder;
58
	/** @var Logger */
59
	private $logger;
60
61
	public function __construct($appname,
62
								IRequest $request,
63
								IURLGenerator $urlGenerator,
64
								TrackBusinessLayer $trackbusinesslayer,
65
								ArtistBusinessLayer $artistbusinesslayer,
66
								AlbumBusinessLayer $albumbusinesslayer,
67
								Cache $cache,
68
								Scanner $scanner,
69
								$userId,
70
								$l10n,
71
								Folder $userFolder,
72
								Logger $logger){
73
		parent::__construct($appname, $request);
74
		$this->l10n = $l10n;
75
		$this->trackBusinessLayer = $trackbusinesslayer;
76
		$this->artistBusinessLayer = $artistbusinesslayer;
77
		$this->albumBusinessLayer = $albumbusinesslayer;
78
		$this->cache = $cache;
79
		$this->scanner = $scanner;
80
		$this->userId = $userId;
81
		$this->urlGenerator = $urlGenerator;
82
		$this->userFolder = $userFolder;
83
		$this->logger = $logger;
84
	}
85
86
	/**
87
	 * Extracts the id from an unique slug (id-slug)
88
	 * @param string $slug the slug
89
	 * @return string the id
90
	 */
91
	protected function getIdFromSlug($slug){
92
		$split = explode('-', $slug, 2);
93
94
		return $split[0];
95
	}
96
97
	/**
98
	 * @NoAdminRequired
99
	 * @NoCSRFRequired
100
	 */
101
	public function collection() {
102
		$collectionJson = $this->cache->get($this->userId, 'collection');
103
104
		if ($collectionJson == null) {
105
			$collectionJson = $this->buildCollectionJson();
106
			$this->cache->add($this->userId, 'collection', $collectionJson);
107
		}
108
		return new DataDisplayResponse($collectionJson);
109
	}
110
111
	private function buildCollectionJson() {
112
		/** @var Artist[] $allArtists */
113
		$allArtists = $this->artistBusinessLayer->findAll($this->userId);
114
		$allArtistsByIdAsObj = array();
115
		$allArtistsByIdAsArr = array();
116
		foreach ($allArtists as &$artist) {
117
			$allArtistsByIdAsObj[$artist->getId()] = $artist;
118
			$allArtistsByIdAsArr[$artist->getId()] = $artist->toCollection($this->l10n);
119
		}
120
		
121
		$allAlbums = $this->albumBusinessLayer->findAll($this->userId);
122
		$allAlbumsByIdAsObj = array();
123
		$allAlbumsByIdAsArr = array();
124
		foreach ($allAlbums as &$album) {
125
			$allAlbumsByIdAsObj[$album->getId()] = $album;
126
			$allAlbumsByIdAsArr[$album->getId()] = $album->toCollection($this->urlGenerator, $this->l10n);
127
		}
128
129
		/** @var Track[] $allTracks */
130
		$allTracks = $this->trackBusinessLayer->findAll($this->userId);
131
132
		$artists = array();
133
		foreach ($allTracks as $track) {
134
			$albumObj = $allAlbumsByIdAsObj[$track->getAlbumId()];
135
			$trackArtistObj = $allArtistsByIdAsObj[$track->getArtistId()];
136
			$track->setAlbum($albumObj);
137
			$track->setArtist($trackArtistObj);
138
139
			$albumArtist = &$allArtistsByIdAsArr[$albumObj->getAlbumArtistId()];
140
			if (!isset($albumArtist['albums'])) {
141
				$albumArtist['albums'] = array();
142
				$artists[] = &$albumArtist;
143
			}
144
			$album = &$allAlbumsByIdAsArr[$track->getAlbumId()];
145
			if (!isset($album['tracks'])) {
146
				$album['tracks'] = array();
147
				$albumArtist['albums'][] = &$album;
148
			}
149
			try {
150
				$album['tracks'][] = $track->toCollection($this->l10n);
151
			} catch (\OCP\Files\NotFoundException $e) {
152
				//ignore not found
153
			}
154
		}
155
		return json_encode($artists);
156
	}
157
158
	/**
159
	 * @NoAdminRequired
160
	 * @NoCSRFRequired
161
	 */
162
	public function artists() {
163
		$fulltree = filter_var($this->params('fulltree'), FILTER_VALIDATE_BOOLEAN);
164
		$includeAlbums = filter_var($this->params('albums'), FILTER_VALIDATE_BOOLEAN);
165
		/** @var Artist[] $artists */
166
		$artists = $this->artistBusinessLayer->findAll($this->userId);
167
		foreach($artists as &$artist) {
168
			$artist = $artist->toAPI($this->urlGenerator, $this->l10n);
169
			if($fulltree || $includeAlbums) {
170
				$artistId = $artist['id'];
171
				$albums = $this->albumBusinessLayer->findAllByArtist($artistId, $this->userId);
172
				foreach($albums as &$album) {
173
					$album = $album->toAPI($this->urlGenerator, $this->l10n);
174
					if($fulltree) {
175
						$albumId = $album['id'];
176
						$tracks = $this->trackBusinessLayer->findAllByAlbum($albumId, $this->userId, $artistId);
177
						foreach($tracks as &$track) {
178
							$track = $track->toAPI($this->urlGenerator);
179
						}
180
						$album['tracks'] = $tracks;
181
					}
182
				}
183
				$artist['albums'] = $albums;
184
			}
185
		}
186
		return new JSONResponse($artists);
187
	}
188
189
	/**
190
	 * @NoAdminRequired
191
	 * @NoCSRFRequired
192
	 */
193 View Code Duplication
	public function artist() {
194
		$fulltree = filter_var($this->params('fulltree'), FILTER_VALIDATE_BOOLEAN);
195
		$artistId = $this->getIdFromSlug($this->params('artistIdOrSlug'));
196
		/** @var Artist $artist */
197
		$artist = $this->artistBusinessLayer->find($artistId, $this->userId);
198
		$artist = $artist->toAPI($this->urlGenerator, $this->l10n);
199
		if($fulltree) {
200
			$artistId = $artist['id'];
201
			$albums = $this->albumBusinessLayer->findAllByArtist($artistId, $this->userId);
202
			foreach($albums as &$album) {
203
				$album = $album->toAPI($this->urlGenerator, $this->l10n);
204
				$albumId = $album['id'];
205
				$tracks = $this->trackBusinessLayer->findAllByAlbum($albumId, $this->userId, $artistId);
206
				foreach($tracks as &$track) {
207
					$track = $track->toAPI($this->urlGenerator);
208
				}
209
				$album['tracks'] = $tracks;
210
			}
211
			$artist['albums'] = $albums;
212
		}
213
		return new JSONResponse($artist);
214
	}
215
216
	/**
217
	 * @NoAdminRequired
218
	 * @NoCSRFRequired
219
	 */
220
	public function albums() {
221
		$fulltree = filter_var($this->params('fulltree'), FILTER_VALIDATE_BOOLEAN);
222
		$albums = $this->albumBusinessLayer->findAll($this->userId);
223
		foreach($albums as &$album) {
224
			$artistIds = $album->getArtistIds();
225
			$album = $album->toAPI($this->urlGenerator, $this->l10n);
226
			if($fulltree) {
227
				$albumId = $album['id'];
228
				$tracks = $this->trackBusinessLayer->findAllByAlbum($albumId, $this->userId);
229
				foreach($tracks as &$track) {
230
					$track = $track->toAPI($this->urlGenerator);
231
				}
232
				$album['tracks'] = $tracks;
233
				$artists = $this->artistBusinessLayer->findMultipleById($artistIds, $this->userId);
234
				foreach($artists as &$artist) {
235
					$artist = $artist->toAPI($this->urlGenerator, $this->l10n);
236
				}
237
				$album['artists'] = $artists;
238
			}
239
		}
240
		return new JSONResponse($albums);
241
	}
242
243
	/**
244
	 * @NoAdminRequired
245
	 * @NoCSRFRequired
246
	 */
247 View Code Duplication
	public function album() {
248
		$fulltree = filter_var($this->params('fulltree'), FILTER_VALIDATE_BOOLEAN);
249
		$albumId = $this->getIdFromSlug($this->params('albumIdOrSlug'));
250
		$album = $this->albumBusinessLayer->find($albumId, $this->userId);
251
252
		$artistIds = $album->getArtistIds();
253
		$album = $album->toAPI($this->urlGenerator, $this->l10n);
254
		if($fulltree) {
255
			$albumId = $album['id'];
256
			$tracks = $this->trackBusinessLayer->findAllByAlbum($albumId, $this->userId);
257
			foreach($tracks as &$track) {
258
				$track = $track->toAPI($this->urlGenerator);
259
			}
260
			$album['tracks'] = $tracks;
261
			$artists = $this->artistBusinessLayer->findMultipleById($artistIds, $this->userId);
262
			foreach($artists as &$artist) {
263
				$artist = $artist->toAPI($this->urlGenerator, $this->l10n);
264
			}
265
			$album['artists'] = $artists;
266
		}
267
268
		return new JSONResponse($album);
269
	}
270
271
	/**
272
	 * @NoAdminRequired
273
	 * @NoCSRFRequired
274
	 */
275
	public function tracks() {
276
		$fulltree = filter_var($this->params('fulltree'), FILTER_VALIDATE_BOOLEAN);
277
		if($artistId = $this->params('artist')) {
278
			$tracks = $this->trackBusinessLayer->findAllByArtist($artistId, $this->userId);
279
		} elseif($albumId = $this->params('album')) {
280
			$tracks = $this->trackBusinessLayer->findAllByAlbum($albumId, $this->userId);
281
		} else {
282
			$tracks = $this->trackBusinessLayer->findAll($this->userId);
283
		}
284
		foreach($tracks as &$track) {
285
			$artistId = $track->getArtistId();
286
			$albumId = $track->getAlbumId();
287
			$track = $track->toAPI($this->urlGenerator);
288
			if($fulltree) {
289
				/** @var Artist $artist */
290
				$artist = $this->artistBusinessLayer->find($artistId, $this->userId);
291
				$track['artist'] = $artist->toAPI($this->urlGenerator, $this->l10n);
292
				$album = $this->albumBusinessLayer->find($albumId, $this->userId);
293
				$track['album'] = $album->toAPI($this->urlGenerator, $this->l10n);
294
			}
295
		}
296
		return new JSONResponse($tracks);
297
	}
298
299
	/**
300
	 * @NoAdminRequired
301
	 * @NoCSRFRequired
302
	 */
303
	public function track() {
304
		$trackId = $this->getIdFromSlug($this->params('trackIdOrSlug'));
305
		/** @var Track $track */
306
		$track = $this->trackBusinessLayer->find($trackId, $this->userId);
307
		return new JSONResponse($track->toAPI($this->urlGenerator));
308
	}
309
310
	/**
311
	 * @NoAdminRequired
312
	 * @NoCSRFRequired
313
	 */
314
	public function trackByFileId() {
315
		$fileId = $this->params('fileId');
316
		$track = $this->trackBusinessLayer->findByFileId($fileId, $this->userId);
317
		$track->setAlbum($this->albumBusinessLayer->find($track->getAlbumId(), $this->userId));
318
		$track->setArtist($this->artistBusinessLayer->find($track->getArtistId(), $this->userId));
319
		return new JSONResponse($track->toCollection($this->l10n));
320
	}
321
322
	/**
323
	 * @NoAdminRequired
324
	 * @NoCSRFRequired
325
	 */
326
	public function fileWebDavUrl() {
327
		$fileId = $this->params('fileId');
328
		$nodes = $this->userFolder->getById($fileId);
329
		if(count($nodes) == 0 ) {
330
			throw new \OCP\Files\NotFoundException();
331
		}
332
333
		$node = $nodes[0];
334
		$relativePath = $this->userFolder->getRelativePath($node->getPath());
335
336
		return new JSONResponse([
337
				'url' => $this->urlGenerator->getAbsoluteUrl('remote.php/webdav' . $relativePath)
338
		]);
339
	}
340
341
	/**
342
	 * @NoAdminRequired
343
	 */
344
	public function getScanState() {
345
		return new JSONResponse([
346
			'unscannedFiles' => $this->scanner->getUnscannedMusicFileIds($this->userId, $this->userFolder),
347
			'scannedCount' => count($this->scanner->getScannedFiles($this->userId))
348
		]);
349
	}
350
351
	/**
352
	 * @NoAdminRequired
353
	 */
354
	public function scan() {
355
		// extract the parameters
356
		$fileIds = array_map('intval', explode(',', $this->params('files')));
357
		$finalize = filter_var($this->params('finalize'), FILTER_VALIDATE_BOOLEAN);
358
359
		$filesScanned = $this->scanner->scanFiles($this->userId, $this->userFolder, $fileIds);
360
361
		$coversUpdated = false;
362
		if ($finalize) {
363
			$coversUpdated = $this->scanner->findCovers();
364
			$totalCount = count($this->scanner->getScannedFiles($this->userId));
365
			$this->logger->log("Scanning finished, user $this->userId has $totalCount scanned tracks in total", 'info');
366
		}
367
368
		return new JSONResponse([
369
			'filesScanned' => $filesScanned,
370
			'coversUpdated' => $coversUpdated
371
		]);
372
	}
373
374
	/**
375
	 * @NoAdminRequired
376
	 * @NoCSRFRequired
377
	 */
378
	public function download() {
379
		// we no longer need the session to be kept open
380
		session_write_close();
381
382
		$fileId = $this->params('fileId');
383
384
		try {
385
			$track = $this->trackBusinessLayer->findByFileId($fileId, $this->userId);
386
		} catch(DoesNotExistException $e) {
387
			$r = new Response();
388
			$r->setStatus(Http::STATUS_NOT_FOUND);
389
			return $r;
390
		}
391
392
		$nodes = $this->userFolder->getById($track->getFileId());
393
		if(count($nodes) > 0 ) {
394
			// get the first valid node
395
			$node = $nodes[0];
396
397
			$mime = $node->getMimeType();
398
			$content = $node->getContent();
399
			return new FileResponse(array('mimetype' => $mime, 'content' => $content));
400
		}
401
402
		$r = new Response();
403
		$r->setStatus(Http::STATUS_NOT_FOUND);
404
		return $r;
405
	}
406
407
	/**
408
	 * @NoAdminRequired
409
	 * @NoCSRFRequired
410
	 */
411
	public function cover() {
412
		// we no longer need the session to be kept open
413
		session_write_close();
414
415
		$albumId = $this->getIdFromSlug($this->params('albumIdOrSlug'));
416
		$album = $this->albumBusinessLayer->find($albumId, $this->userId);
417
418
		$nodes = $this->userFolder->getById($album->getCoverFileId());
419
		if(count($nodes) > 0 ) {
420
			// get the first valid node
421
			$node = $nodes[0];
422
			$mime = $node->getMimeType();
423
424
			if (0 === strpos($mime, 'audio')) { // embedded cover image
425
				$cover = $this->scanner->parseEmbeddedCoverArt($node);
426
427
				if($cover != null) {
428
					return new FileResponse(array(
429
							'mimetype' => $cover["image_mime"],
430
							'content' => $cover["data"]
431
					));
432
				}
433
			}
434
			else { // separate image file
435
				$content = $node->getContent();
436
				return new FileResponse(array('mimetype' => $mime, 'content' => $content));
437
			}
438
		}
439
440
		$r = new Response();
441
		$r->setStatus(Http::STATUS_NOT_FOUND);
442
		return $r;
443
	}
444
}
445