Passed
Push — feature/909_Ampache_API_improv... ( 673c0e...814067 )
by Pauli
02:45
created

Library::injectAlbumsToArtists()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 10
c 0
b 0
f 0
nc 4
nop 2
dl 0
loc 15
rs 9.9332
1
<?php declare(strict_types=1);
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 Pauli Järvinen <[email protected]>
10
 * @copyright Pauli Järvinen 2018 - 2023
11
 */
12
13
namespace OCA\Music\BusinessLayer;
14
15
use OCA\Music\AppFramework\Core\Logger;
16
use OCA\Music\Utility\CoverHelper;
17
use OCA\Music\Utility\Util;
18
19
use OCP\IL10N;
20
use OCP\IURLGenerator;
21
22
class Library {
23
	private $albumBusinessLayer;
24
	private $artistBusinessLayer;
25
	private $trackBusinessLayer;
26
	private $coverHelper;
27
	private $urlGenerator;
28
	private $l10n;
29
	private $logger;
30
31
	public function __construct(
32
			AlbumBusinessLayer $albumBusinessLayer,
33
			ArtistBusinessLayer $artistBusinessLayer,
34
			TrackBusinessLayer $trackBusinessLayer,
35
			CoverHelper $coverHelper,
36
			IURLGenerator $urlGenerator,
37
			IL10N $l10n,
38
			Logger $logger) {
39
		$this->albumBusinessLayer = $albumBusinessLayer;
40
		$this->artistBusinessLayer = $artistBusinessLayer;
41
		$this->trackBusinessLayer = $trackBusinessLayer;
42
		$this->coverHelper = $coverHelper;
43
		$this->urlGenerator = $urlGenerator;
44
		$this->l10n = $l10n;
45
		$this->logger = $logger;
46
	}
47
48
	public function getTracksAlbumsAndArtists($userId) {
49
		// Get all the entities from the DB first. The order of queries is important if we are in
50
		// the middle of a scanning process: we don't want to get tracks which do not yet have
51
		// an album entry or albums which do not yet have artist entry.
52
		$tracks = $this->trackBusinessLayer->findAll($userId);
53
		$albums = $this->albumBusinessLayer->findAll($userId);
54
		$artists = $this->artistBusinessLayer->findAll($userId);
55
56
		$artistsById = Util::createIdLookupTable($artists);
57
		$albumsById = Util::createIdLookupTable($albums);
58
59
		foreach ($tracks as $idx => $track) {
60
			$album = $albumsById[$track->getAlbumId()];
61
62
			if (empty($album)) {
63
				$this->logger->log("DB error on track {$track->id} '{$track->title}': ".
64
				"album with ID {$track->albumId} not found. Skipping the track.", 'warn');
65
				unset($tracks[$idx]);
66
			} else {
67
				$track->setAlbum($album);
68
			}
69
		}
70
71
		return [
72
			'tracks' => $tracks,
73
			'albums' => $albumsById,
74
			'artists' => $artistsById
75
		];
76
	}
77
78
	public function toCollection($userId) {
79
		$entities = $this->getTracksAlbumsAndArtists($userId);
80
		$coverHashes = $this->coverHelper->getAllCachedAlbumCoverHashes($userId);
81
82
		// Create a multi-level dictionary of tracks where each track can be found
83
		// by addressing like $trackDict[artistId][albumId][ordinal]. The tracks are
84
		// in the dictionary in the "toCollection" format.
85
		$trackDict = [];
86
		foreach ($entities['tracks'] as $track) {
87
			$trackDict[$track->getAlbum()->getAlbumArtistId()][$track->getAlbumId()][]
88
				= $track->toCollection();
89
		}
90
91
		// Then create the actual collection by iterating over the previusly created
92
		// dictionary and creating artists and albums in the "toCollection" format.
93
		$collection = [];
94
		foreach ($trackDict as $artistId => $artistTracksByAlbum) {
95
			$artistAlbums = [];
96
			foreach ($artistTracksByAlbum as $albumId => $albumTracks) {
97
				$coverHash = $coverHashes[$albumId] ?? null;
98
				$artistAlbums[] = $entities['albums'][$albumId]->toCollection(
99
						$this->urlGenerator, $this->l10n, $coverHash, $albumTracks);
100
			}
101
102
			$collection[] = $entities['artists'][$artistId]->toCollection($this->l10n, $artistAlbums);
103
		}
104
105
		// Add the artists with no own albums to the collection
106
		foreach ($entities['artists'] as $artist) {
107
			if (!isset($trackDict[$artist->getId()])) {
108
				$collection[] = $artist->toCollection($this->l10n, []);
109
			}
110
		}
111
112
		return $collection;
113
	}
114
115
	/**
116
	 * Get the timestamp of the latest insert operation on the library
117
	 */
118
	public function latestInsertTime(string $userId) : \DateTime {
119
		return \max(
120
			$this->artistBusinessLayer->latestInsertTime($userId),
121
			$this->albumBusinessLayer->latestInsertTime($userId),
122
			$this->trackBusinessLayer->latestInsertTime($userId)
123
		);
124
	}
125
126
	/**
127
	 * Get the timestamp of the latest update operation on the library
128
	 */
129
	public function latestUpdateTime(string $userId) : \DateTime {
130
		return \max(
131
			$this->artistBusinessLayer->latestUpdateTime($userId),
132
			$this->albumBusinessLayer->latestUpdateTime($userId),
133
			$this->trackBusinessLayer->latestUpdateTime($userId)
134
		);
135
	}
136
137
	/**
138
	 * Inject tracks to the given albums. Sets also the album refence of each injected track.
139
	 * @param Album[] $albums input/output
140
	 */
141
	public function injectTracksToAlbums(array &$albums, string $userId) : void {
142
		$alBussLayer = $this->albumBusinessLayer;
143
		$trBussLayer = $this->trackBusinessLayer;
144
145
		if (\count($albums) < $alBussLayer::MAX_SQL_ARGS && \count($albums) < $alBussLayer->count($userId)) {
146
			$tracks = $trBussLayer->findAllByAlbum(Util::extractIds($albums), $userId);
147
		} else {
148
			$tracks = $trBussLayer->findAll($userId);
149
		}
150
151
		$tracksPerAlbum = Util::arrayGroupBy($tracks, 'getAlbumId');
152
153
		foreach ($albums as &$album) {
154
			$albumTracks = $tracksPerAlbum[$album->getId()] ?? [];
155
			$album->setTracks($albumTracks);
156
			foreach ($albumTracks as &$track) {
157
				$track->setAlbum($album);
158
			}
159
		}
160
	}
161
162
	/**
163
	 * Inject tracks to the given artists
164
	 * @param Artist[] $artists input/output
165
	 */
166
	public function injectTracksToArtists(array &$artists, string $userId) : void {
167
		$arBussLayer = $this->artistBusinessLayer;
168
		$trBussLayer = $this->trackBusinessLayer;
169
170
		if (\count($artists) < $arBussLayer::MAX_SQL_ARGS && \count($artists) < $arBussLayer->count($userId)) {
171
			$tracks = $trBussLayer->findAllByArtist(Util::extractIds($artists), $userId);
172
		} else {
173
			$tracks = $trBussLayer->findAll($userId);
174
		}
175
176
		$tracksPerArtist = Util::arrayGroupBy($tracks, 'getArtistId');
177
178
		foreach ($artists as &$artist) {
179
			$artistTracks = $tracksPerArtist[$artist->getId()] ?? [];
180
			$artist->setTracks($artistTracks);
181
		}
182
	}
183
184
	/**
185
	 * Inject albums to the given artists
186
	 * @param Artist[] $artists input/output
187
	 */
188
	public function injectAlbumsToArtists(array &$artists, string $userId) : void {
189
		$arBussLayer = $this->artistBusinessLayer;
190
		$alBussLayer = $this->albumBusinessLayer;
191
192
		if (\count($artists) < $arBussLayer::MAX_SQL_ARGS && \count($artists) < $arBussLayer->count($userId)) {
193
			$albums = $alBussLayer->findAllByAlbumArtist(Util::extractIds($artists), $userId);
194
		} else {
195
			$albums = $alBussLayer->findAll($userId);
196
		}
197
198
		$albumsPerArtist = Util::arrayGroupBy($albums, 'getAlbumArtistId');
199
200
		foreach ($artists as &$artist) {
201
			$artistAlbums = $albumsPerArtist[$artist->getId()] ?? [];
202
			$artist->setAlbums($artistAlbums);
203
		}
204
	}
205
}
206