Passed
Push — master ( a41398...d259a4 )
by Pauli
02:48
created

PlaylistBusinessLayer::setTracks()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 3
dl 0
loc 5
rs 10
c 0
b 0
f 0
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 2016 - 2021
11
 */
12
13
namespace OCA\Music\BusinessLayer;
14
15
use \OCA\Music\AppFramework\BusinessLayer\BusinessLayer;
16
use \OCA\Music\AppFramework\Core\Logger;
17
18
use \OCA\Music\Db\Playlist;
19
use \OCA\Music\Db\PlaylistMapper;
20
use \OCA\Music\Db\Track;
21
use \OCA\Music\Db\TrackMapper;
22
23
use \OCA\Music\Utility\Util;
24
25
/**
26
 * Base class functions with actually used inherited types to help IDE and Scrutinizer:
27
 * @method Playlist find(int $playlistId, string $userId)
28
 * @method Playlist[] findAll(string $userId, int $sortBy=SortBy::None, int $limit=null, int $offset=null)
29
 * @method Playlist[] findAllByName(string $name, string $userId, bool $fuzzy=false, int $limit=null, int $offset=null)
30
 */
31
class PlaylistBusinessLayer extends BusinessLayer {
32
	protected $mapper; // eclipse the definition from the base class, to help IDE and Scrutinizer to know the actual type
33
	private $trackMapper;
34
	private $logger;
35
36
	public function __construct(
37
			PlaylistMapper $playlistMapper,
38
			TrackMapper $trackMapper,
39
			Logger $logger) {
40
		parent::__construct($playlistMapper);
41
		$this->mapper = $playlistMapper;
42
		$this->trackMapper = $trackMapper;
43
		$this->logger = $logger;
44
	}
45
46
	public function setTracks($trackIds, $playlistId, $userId) {
47
		$playlist = $this->find($playlistId, $userId);
48
		$playlist->setTrackIdsFromArray($trackIds);
49
		$this->mapper->update($playlist);
50
		return $playlist;
51
	}
52
53
	public function addTracks($trackIds, $playlistId, $userId) {
54
		$playlist = $this->find($playlistId, $userId);
55
		$prevTrackIds = $playlist->getTrackIdsAsArray();
56
		$playlist->setTrackIdsFromArray(\array_merge($prevTrackIds, $trackIds));
57
		$this->mapper->update($playlist);
58
		return $playlist;
59
	}
60
61
	public function removeTracks($trackIndices, $playlistId, $userId) {
62
		$playlist = $this->find($playlistId, $userId);
63
		$trackIds = $playlist->getTrackIdsAsArray();
64
		$trackIds = \array_diff_key($trackIds, \array_flip($trackIndices));
65
		$playlist->setTrackIdsFromArray($trackIds);
66
		$this->mapper->update($playlist);
67
		return $playlist;
68
	}
69
70
	public function moveTrack($fromIndex, $toIndex, $playlistId, $userId) {
71
		$playlist = $this->find($playlistId, $userId);
72
		$trackIds = $playlist->getTrackIdsAsArray();
73
		$movedTrack = \array_splice($trackIds, $fromIndex, 1);
74
		\array_splice($trackIds, $toIndex, 0, $movedTrack);
75
		$playlist->setTrackIdsFromArray($trackIds);
76
		$this->mapper->update($playlist);
77
		return $playlist;
78
	}
79
80
	public function create($name, $userId) {
81
		$playlist = new Playlist();
82
		$playlist->setName(Util::truncate($name, 256)); // some DB setups can't truncate automatically to column max size
83
		$playlist->setUserId($userId);
84
85
		return $this->mapper->insert($playlist);
86
	}
87
88
	public function rename($name, $playlistId, $userId) {
89
		$playlist = $this->find($playlistId, $userId);
90
		$playlist->setName(Util::truncate($name, 256)); // some DB setups can't truncate automatically to column max size
91
		$this->mapper->update($playlist);
92
		return $playlist;
93
	}
94
95
	public function setComment($comment, $playlistId, $userId) {
96
		$playlist = $this->find($playlistId, $userId);
97
		$playlist->setComment(Util::truncate($comment, 256)); // some DB setups can't truncate automatically to column max size
98
		$this->mapper->update($playlist);
99
		return $playlist;
100
	}
101
102
	/**
103
	 * removes tracks from all available playlists
104
	 * @param int[] $trackIds array of all track IDs to remove
105
	 */
106
	public function removeTracksFromAllLists($trackIds) {
107
		foreach ($trackIds as $trackId) {
108
			$affectedLists = $this->mapper->findListsContainingTrack($trackId);
109
110
			foreach ($affectedLists as $playlist) {
111
				$prevTrackIds = $playlist->getTrackIdsAsArray();
112
				$playlist->setTrackIdsFromArray(\array_diff($prevTrackIds, [$trackId]));
113
				$this->mapper->update($playlist);
114
			}
115
		}
116
	}
117
118
	/**
119
	 * get list of Track objects belonging to a given playlist
120
	 * @param int $playlistId
121
	 * @param string $userId
122
	 * @param int|null $limit
123
	 * @param int|null $offset
124
	 * @return Track[]
125
	 */
126
	public function getPlaylistTracks($playlistId, $userId, $limit=null, $offset=null) {
127
		$playlist = $this->find($playlistId, $userId);
128
		$trackIds = $playlist->getTrackIdsAsArray();
129
130
		$trackIds = \array_slice($trackIds, \intval($offset), $limit);
131
132
		$tracks = empty($trackIds) ? [] : $this->trackMapper->findById($trackIds, $userId);
133
134
		// The $tracks contains the songs in unspecified order and with no duplicates.
135
		// Build a new array where the tracks are in the same order as in $trackIds.
136
		$tracksById = Util::createIdLookupTable($tracks);
137
138
		$playlistTracks = [];
139
		foreach ($trackIds as $index => $trackId) {
140
			$track = $tracksById[$trackId] ?? null;
141
			if ($track !== null) {
142
				// in case the same track comes up again in the list, clone the track object
143
				// to have different numbers on the instances
144
				if ($track->getNumberOnPlaylist() !== null) {
145
					$track = clone $track;
146
				}
147
				$track->setNumberOnPlaylist(\intval($offset) + $index + 1);
148
			} else {
149
				$this->logger->log("Invalid track ID $trackId found on playlist $playlistId", 'debug');
150
				$track = new Track();
151
				$track->setId($trackId);
152
			}
153
			$playlistTracks[] = $track;
154
		}
155
156
		return $playlistTracks;
157
	}
158
159
	/**
160
	 * get the total duration of all the tracks on a playlist
161
	 *
162
	 * @param int $playlistId
163
	 * @param string $userId
164
	 * @return int duration in seconds
165
	 */
166
	public function getDuration($playlistId, $userId) {
167
		$playlist = $this->find($playlistId, $userId);
168
		$trackIds = $playlist->getTrackIdsAsArray();
169
		$durations = $this->trackMapper->getDurations($trackIds);
170
171
		// We can't simply sum up the values of $durations array, because the playlist may
172
		// contain duplicate entries, and those are not reflected in $durations.
173
		// Be also prepared to invalid playlist entries where corresponding track length does not exist.
174
		$sum = 0;
175
		foreach ($trackIds as $trackId) {
176
			$sum += $durations[$trackId] ?? 0;
177
		}
178
179
		return $sum;
180
	}
181
}
182