nc-music /
music
| 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 Morris Jobke <[email protected]> |
||||
| 10 | * @author Pauli Järvinen <[email protected]> |
||||
| 11 | * @copyright Morris Jobke 2013, 2014 |
||||
| 12 | * @copyright Pauli Järvinen 2016 - 2025 |
||||
| 13 | */ |
||||
| 14 | |||||
| 15 | namespace OCA\Music\Db; |
||||
| 16 | |||||
| 17 | use OCA\Music\Utility\ArrayUtil; |
||||
| 18 | use OCA\Music\Utility\StringUtil; |
||||
| 19 | |||||
| 20 | use OCP\IConfig; |
||||
| 21 | use OCP\IDBConnection; |
||||
| 22 | |||||
| 23 | /** |
||||
| 24 | * Type hint a base class method to help Scrutinizer |
||||
| 25 | * @method Album updateOrInsert(Album $album) |
||||
| 26 | * @extends BaseMapper<Album> |
||||
| 27 | */ |
||||
| 28 | class AlbumMapper extends BaseMapper { |
||||
| 29 | public function __construct(IDBConnection $db, IConfig $config) { |
||||
| 30 | parent::__construct($db, $config, 'music_albums', Album::class, 'name', ['user_id', 'hash'], 'album_artist_id'); |
||||
| 31 | } |
||||
| 32 | |||||
| 33 | /** |
||||
| 34 | * Override the base implementation to include data from multiple tables |
||||
| 35 | * |
||||
| 36 | * {@inheritdoc} |
||||
| 37 | * @see BaseMapper::selectEntities() |
||||
| 38 | */ |
||||
| 39 | protected function selectEntities(string $condition, ?string $extension=null) : string { |
||||
| 40 | return "SELECT `*PREFIX*music_albums`.*, `artist`.`name` AS `album_artist_name` |
||||
| 41 | FROM `*PREFIX*music_albums` |
||||
| 42 | INNER JOIN `*PREFIX*music_artists` `artist` |
||||
| 43 | ON `*PREFIX*music_albums`.`album_artist_id` = `artist`.`id` |
||||
| 44 | WHERE $condition $extension"; |
||||
| 45 | } |
||||
| 46 | |||||
| 47 | /** |
||||
| 48 | * Overridden from \OCA\Music\Db\BaseMapper to add support for sorting by artist. |
||||
| 49 | * |
||||
| 50 | * {@inheritdoc} |
||||
| 51 | * @see BaseMapper::formatSortingClause() |
||||
| 52 | */ |
||||
| 53 | protected function formatSortingClause(int $sortBy, bool $invertSort = false) : ?string { |
||||
| 54 | if ($sortBy === SortBy::Parent) { |
||||
| 55 | // Note: the alternative form "LOWER(`album_artist_name`) wouldn't work on PostgreSQL, see https://github.com/owncloud/music/issues/1046 |
||||
| 56 | $dir = $invertSort ? 'DESC' : 'ASC'; |
||||
| 57 | return "ORDER BY LOWER(`artist`.`name`) $dir, LOWER(`*PREFIX*music_albums`.`name`) $dir"; |
||||
| 58 | } else { |
||||
| 59 | return parent::formatSortingClause($sortBy, $invertSort); |
||||
| 60 | } |
||||
| 61 | } |
||||
| 62 | |||||
| 63 | /** |
||||
| 64 | * returns artist IDs mapped to album IDs |
||||
| 65 | * does not include album_artist_id |
||||
| 66 | * |
||||
| 67 | * @param integer[]|null $albumIds IDs of the albums; get all albums of the user if null given |
||||
| 68 | * @param string $userId the user ID |
||||
| 69 | * @return array<int, int[]> keys are albums IDs and values are arrays of artist IDs |
||||
| 70 | */ |
||||
| 71 | public function getPerformingArtistsByAlbumId(?array $albumIds, string $userId) : array { |
||||
| 72 | $sql = 'SELECT DISTINCT `track`.`album_id`, `track`.`artist_id` |
||||
| 73 | FROM `*PREFIX*music_tracks` `track` |
||||
| 74 | WHERE `track`.`user_id` = ? '; |
||||
| 75 | $params = [$userId]; |
||||
| 76 | |||||
| 77 | if ($albumIds !== null) { |
||||
|
0 ignored issues
–
show
introduced
by
Loading history...
|
|||||
| 78 | $sql .= 'AND `track`.`album_id` IN ' . $this->questionMarks(\count($albumIds)); |
||||
| 79 | $params = \array_merge($params, $albumIds); |
||||
| 80 | } |
||||
| 81 | |||||
| 82 | $result = $this->execute($sql, $params); |
||||
| 83 | $artistIds = []; |
||||
| 84 | while ($row = $result->fetch()) { |
||||
|
0 ignored issues
–
show
The function
OCP\DB\IPreparedStatement::fetch() has been deprecated: 21.0.0 use \OCP\DB\IResult::fetch on the \OCP\DB\IResult returned by \OCP\IDBConnection::prepare
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. Loading history...
|
|||||
| 85 | $artistIds[$row['album_id']][] = (int)$row['artist_id']; |
||||
| 86 | } |
||||
| 87 | $result->closeCursor(); |
||||
|
0 ignored issues
–
show
The function
OCP\DB\IPreparedStatement::closeCursor() has been deprecated: 21.0.0 use \OCP\DB\IResult::closeCursor on the \OCP\DB\IResult returned by \OCP\IDBConnection::prepare
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. Loading history...
|
|||||
| 88 | return $artistIds; |
||||
| 89 | } |
||||
| 90 | |||||
| 91 | /** |
||||
| 92 | * returns release years mapped to album IDs |
||||
| 93 | * |
||||
| 94 | * @param integer[]|null $albumIds IDs of the albums; get all albums of the user if null given |
||||
| 95 | * @param string $userId the user ID |
||||
| 96 | * @return array<int, int[]> keys are albums IDs and values are arrays of years |
||||
| 97 | */ |
||||
| 98 | public function getYearsByAlbumId(?array $albumIds, string $userId) : array { |
||||
| 99 | $sql = 'SELECT DISTINCT `track`.`album_id`, `track`.`year` |
||||
| 100 | FROM `*PREFIX*music_tracks` `track` |
||||
| 101 | WHERE `track`.`user_id` = ? |
||||
| 102 | AND `track`.`year` IS NOT NULL '; |
||||
| 103 | $params = [$userId]; |
||||
| 104 | |||||
| 105 | if ($albumIds !== null) { |
||||
|
0 ignored issues
–
show
|
|||||
| 106 | $sql .= 'AND `track`.`album_id` IN ' . $this->questionMarks(\count($albumIds)); |
||||
| 107 | $params = \array_merge($params, $albumIds); |
||||
| 108 | } |
||||
| 109 | |||||
| 110 | $result = $this->execute($sql, $params); |
||||
| 111 | $years = []; |
||||
| 112 | while ($row = $result->fetch()) { |
||||
|
0 ignored issues
–
show
The function
OCP\DB\IPreparedStatement::fetch() has been deprecated: 21.0.0 use \OCP\DB\IResult::fetch on the \OCP\DB\IResult returned by \OCP\IDBConnection::prepare
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. Loading history...
|
|||||
| 113 | $years[$row['album_id']][] = (int)$row['year']; |
||||
| 114 | } |
||||
| 115 | $result->closeCursor(); |
||||
|
0 ignored issues
–
show
The function
OCP\DB\IPreparedStatement::closeCursor() has been deprecated: 21.0.0 use \OCP\DB\IResult::closeCursor on the \OCP\DB\IResult returned by \OCP\IDBConnection::prepare
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. Loading history...
|
|||||
| 116 | return $years; |
||||
| 117 | } |
||||
| 118 | |||||
| 119 | /** |
||||
| 120 | * returns genres mapped to album IDs |
||||
| 121 | * |
||||
| 122 | * @param integer[]|null $albumIds IDs of the albums; get all albums of the user if null given |
||||
| 123 | * @param string $userId the user ID |
||||
| 124 | * @return array<int, Genre[]> keys are albums IDs and values are arrays of *partial* Genre objects (only id and name properties set) |
||||
| 125 | */ |
||||
| 126 | public function getGenresByAlbumId(?array $albumIds, string $userId) : array { |
||||
| 127 | $sql = 'SELECT DISTINCT `album_id`, `genre_id`, `*PREFIX*music_genres`.`name` AS `genre_name` |
||||
| 128 | FROM `*PREFIX*music_tracks` |
||||
| 129 | LEFT JOIN `*PREFIX*music_genres` |
||||
| 130 | ON `genre_id` = `*PREFIX*music_genres`.`id` |
||||
| 131 | WHERE `*PREFIX*music_tracks`.`user_id` = ? |
||||
| 132 | AND `genre_id` IS NOT NULL '; |
||||
| 133 | $params = [$userId]; |
||||
| 134 | |||||
| 135 | if ($albumIds !== null) { |
||||
|
0 ignored issues
–
show
|
|||||
| 136 | $sql .= 'AND `album_id` IN ' . $this->questionMarks(\count($albumIds)); |
||||
| 137 | $params = \array_merge($params, $albumIds); |
||||
| 138 | } |
||||
| 139 | |||||
| 140 | $result = $this->execute($sql, $params); |
||||
| 141 | $genres = []; |
||||
| 142 | while ($row = $result->fetch()) { |
||||
|
0 ignored issues
–
show
The function
OCP\DB\IPreparedStatement::fetch() has been deprecated: 21.0.0 use \OCP\DB\IResult::fetch on the \OCP\DB\IResult returned by \OCP\IDBConnection::prepare
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. Loading history...
|
|||||
| 143 | $genre = new Genre(); |
||||
| 144 | $genre->setUserId($userId); |
||||
| 145 | $genre->setId((int)$row['genre_id']); |
||||
| 146 | $genre->setName($row['genre_name']); |
||||
| 147 | $genres[$row['album_id']][] = $genre; |
||||
| 148 | } |
||||
| 149 | $result->closeCursor(); |
||||
|
0 ignored issues
–
show
The function
OCP\DB\IPreparedStatement::closeCursor() has been deprecated: 21.0.0 use \OCP\DB\IResult::closeCursor on the \OCP\DB\IResult returned by \OCP\IDBConnection::prepare
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. Loading history...
|
|||||
| 150 | return $genres; |
||||
| 151 | } |
||||
| 152 | |||||
| 153 | /** |
||||
| 154 | * returns number of disks per album ID |
||||
| 155 | * |
||||
| 156 | * @param integer[]|null $albumIds IDs of the albums; get all albums of the user if null given |
||||
| 157 | * @param string $userId the user ID |
||||
| 158 | * @return array<int, int> keys are albums IDs and values are disk counts |
||||
| 159 | */ |
||||
| 160 | public function getDiscCountByAlbumId(?array $albumIds, string $userId) : array { |
||||
| 161 | $sql = 'SELECT `album_id`, MAX(`disk`) AS `disc_count` |
||||
| 162 | FROM `*PREFIX*music_tracks` |
||||
| 163 | WHERE `user_id` = ? |
||||
| 164 | GROUP BY `album_id` '; |
||||
| 165 | $params = [$userId]; |
||||
| 166 | |||||
| 167 | if ($albumIds !== null) { |
||||
|
0 ignored issues
–
show
|
|||||
| 168 | $sql .= 'HAVING `album_id` IN ' . $this->questionMarks(\count($albumIds)); |
||||
| 169 | $params = \array_merge($params, $albumIds); |
||||
| 170 | } |
||||
| 171 | |||||
| 172 | $result = $this->execute($sql, $params); |
||||
| 173 | $diskCountByAlbum = []; |
||||
| 174 | while ($row = $result->fetch()) { |
||||
|
0 ignored issues
–
show
The function
OCP\DB\IPreparedStatement::fetch() has been deprecated: 21.0.0 use \OCP\DB\IResult::fetch on the \OCP\DB\IResult returned by \OCP\IDBConnection::prepare
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. Loading history...
|
|||||
| 175 | $diskCountByAlbum[$row['album_id']] = (int)$row['disc_count']; |
||||
| 176 | } |
||||
| 177 | $result->closeCursor(); |
||||
|
0 ignored issues
–
show
The function
OCP\DB\IPreparedStatement::closeCursor() has been deprecated: 21.0.0 use \OCP\DB\IResult::closeCursor on the \OCP\DB\IResult returned by \OCP\IDBConnection::prepare
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. Loading history...
|
|||||
| 178 | return $diskCountByAlbum; |
||||
| 179 | } |
||||
| 180 | |||||
| 181 | /** |
||||
| 182 | * returns summed track play counts of each album of the user, omitting albums which have never been played |
||||
| 183 | * |
||||
| 184 | * @return array<int, int> keys are album IDs and values are play count sums; ordered largest counts first |
||||
| 185 | */ |
||||
| 186 | public function getAlbumTracksPlayCount(string $userId, ?int $limit=null, ?int $offset=null) : array { |
||||
| 187 | $sql = 'SELECT `album_id`, SUM(`play_count`) AS `sum_count` |
||||
| 188 | FROM `*PREFIX*music_tracks` |
||||
| 189 | WHERE `user_id` = ? AND `play_count` > 0 |
||||
| 190 | GROUP BY `album_id` |
||||
| 191 | ORDER BY `sum_count` DESC, `album_id`'; // the second criterion is just to make the order predictable on even counts |
||||
| 192 | |||||
| 193 | $result = $this->execute($sql, [$userId], $limit, $offset); |
||||
| 194 | $playCountByAlbum = []; |
||||
| 195 | while ($row = $result->fetch()) { |
||||
|
0 ignored issues
–
show
The function
OCP\DB\IPreparedStatement::fetch() has been deprecated: 21.0.0 use \OCP\DB\IResult::fetch on the \OCP\DB\IResult returned by \OCP\IDBConnection::prepare
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. Loading history...
|
|||||
| 196 | $playCountByAlbum[$row['album_id']] = (int)$row['sum_count']; |
||||
| 197 | } |
||||
| 198 | $result->closeCursor(); |
||||
|
0 ignored issues
–
show
The function
OCP\DB\IPreparedStatement::closeCursor() has been deprecated: 21.0.0 use \OCP\DB\IResult::closeCursor on the \OCP\DB\IResult returned by \OCP\IDBConnection::prepare
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. Loading history...
|
|||||
| 199 | return $playCountByAlbum; |
||||
| 200 | } |
||||
| 201 | |||||
| 202 | /** |
||||
| 203 | * returns the latest play time of each album of the user, omitting albums which have never been played |
||||
| 204 | * |
||||
| 205 | * @return array<int, string> keys are album IDs and values are date-times; ordered latest times first |
||||
| 206 | */ |
||||
| 207 | public function getLatestAlbumPlayTimes(string $userId, ?int $limit=null, ?int $offset=null) : array { |
||||
| 208 | $sql = 'SELECT `album_id`, MAX(`last_played`) AS `latest_time` |
||||
| 209 | FROM `*PREFIX*music_tracks` |
||||
| 210 | WHERE `user_id` = ? AND `last_played` IS NOT NULL |
||||
| 211 | GROUP BY `album_id` |
||||
| 212 | ORDER BY `latest_time` DESC'; |
||||
| 213 | |||||
| 214 | $result = $this->execute($sql, [$userId], $limit, $offset); |
||||
| 215 | $latestTimeByAlbum = []; |
||||
| 216 | while ($row = $result->fetch()) { |
||||
|
0 ignored issues
–
show
The function
OCP\DB\IPreparedStatement::fetch() has been deprecated: 21.0.0 use \OCP\DB\IResult::fetch on the \OCP\DB\IResult returned by \OCP\IDBConnection::prepare
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. Loading history...
|
|||||
| 217 | $latestTimeByAlbum[$row['album_id']] = $row['latest_time']; |
||||
| 218 | } |
||||
| 219 | $result->closeCursor(); |
||||
|
0 ignored issues
–
show
The function
OCP\DB\IPreparedStatement::closeCursor() has been deprecated: 21.0.0 use \OCP\DB\IResult::closeCursor on the \OCP\DB\IResult returned by \OCP\IDBConnection::prepare
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. Loading history...
|
|||||
| 220 | return $latestTimeByAlbum; |
||||
| 221 | } |
||||
| 222 | |||||
| 223 | /** |
||||
| 224 | * returns the latest play time of each album of the user, including albums which have never been played |
||||
| 225 | * |
||||
| 226 | * @return array<int, ?string> keys are album IDs and values are date-times (or null for never played); |
||||
| 227 | * ordered furthest times first |
||||
| 228 | */ |
||||
| 229 | public function getFurthestAlbumPlayTimes(string $userId, ?int $limit=null, ?int $offset=null) : array { |
||||
| 230 | $sql = 'SELECT `album_id`, MAX(`last_played`) AS `latest_time` |
||||
| 231 | FROM `*PREFIX*music_tracks` |
||||
| 232 | WHERE `user_id` = ? |
||||
| 233 | GROUP BY `album_id` |
||||
| 234 | ORDER BY `latest_time` ASC'; |
||||
| 235 | |||||
| 236 | $result = $this->execute($sql, [$userId], $limit, $offset); |
||||
| 237 | $latestTimeByAlbum = []; |
||||
| 238 | while ($row = $result->fetch()) { |
||||
|
0 ignored issues
–
show
The function
OCP\DB\IPreparedStatement::fetch() has been deprecated: 21.0.0 use \OCP\DB\IResult::fetch on the \OCP\DB\IResult returned by \OCP\IDBConnection::prepare
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. Loading history...
|
|||||
| 239 | $latestTimeByAlbum[$row['album_id']] = $row['latest_time']; |
||||
| 240 | } |
||||
| 241 | $result->closeCursor(); |
||||
|
0 ignored issues
–
show
The function
OCP\DB\IPreparedStatement::closeCursor() has been deprecated: 21.0.0 use \OCP\DB\IResult::closeCursor on the \OCP\DB\IResult returned by \OCP\IDBConnection::prepare
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. Loading history...
|
|||||
| 242 | return $latestTimeByAlbum; |
||||
| 243 | } |
||||
| 244 | |||||
| 245 | /** |
||||
| 246 | * @return Album[] |
||||
| 247 | */ |
||||
| 248 | public function findAllByNameRecursive(string $name, string $userId, ?int $limit=null, ?int $offset=null) : array { |
||||
| 249 | $condition = '( LOWER(`artist`.`name`) LIKE LOWER(?) OR |
||||
| 250 | LOWER(`*PREFIX*music_albums`.`name`) LIKE LOWER(?) )'; |
||||
| 251 | $sql = $this->selectUserEntities($condition, 'ORDER BY LOWER(`*PREFIX*music_albums`.`name`)'); |
||||
| 252 | $name = BaseMapper::prepareSubstringSearchPattern($name); |
||||
| 253 | $params = [$userId, $name, $name]; |
||||
| 254 | return $this->findEntities($sql, $params, $limit, $offset); |
||||
| 255 | } |
||||
| 256 | |||||
| 257 | /** |
||||
| 258 | * returns albums of a specified artist |
||||
| 259 | * The artist may be an album_artist or the artist of a track |
||||
| 260 | * |
||||
| 261 | * @param integer $artistId |
||||
| 262 | * @return Album[] |
||||
| 263 | */ |
||||
| 264 | public function findAllByArtist(int $artistId, string $userId, ?int $limit=null, ?int $offset=null) : array { |
||||
| 265 | $sql = $this->selectEntities( |
||||
| 266 | '`*PREFIX*music_albums`.`id` IN ( |
||||
| 267 | SELECT DISTINCT `album`.`id` |
||||
| 268 | FROM `*PREFIX*music_albums` `album` |
||||
| 269 | WHERE `album`.`album_artist_id` = ? |
||||
| 270 | UNION |
||||
| 271 | SELECT DISTINCT `track`.`album_id` |
||||
| 272 | FROM `*PREFIX*music_tracks` `track` |
||||
| 273 | WHERE `track`.`artist_id` = ? |
||||
| 274 | ) AND `*PREFIX*music_albums`.`user_id` = ?', |
||||
| 275 | 'ORDER BY LOWER(`*PREFIX*music_albums`.`name`)'); |
||||
| 276 | $params = [$artistId, $artistId, $userId]; |
||||
| 277 | return $this->findEntities($sql, $params, $limit, $offset); |
||||
| 278 | } |
||||
| 279 | |||||
| 280 | /** |
||||
| 281 | * returns albums of a specified artists |
||||
| 282 | * The artist must be album_artist on the album, artists of individual tracks are not considered |
||||
| 283 | * |
||||
| 284 | * @param int[] $artistIds |
||||
| 285 | * @return Album[] |
||||
| 286 | */ |
||||
| 287 | public function findAllByAlbumArtist(array $artistIds, string $userId, ?int $limit=null, ?int $offset=null) : array { |
||||
| 288 | $sql = $this->selectUserEntities('`album_artist_id` IN ' . $this->questionMarks(\count($artistIds))); |
||||
| 289 | $params = \array_merge([$userId], $artistIds); |
||||
| 290 | return $this->findEntities($sql, $params, $limit, $offset); |
||||
| 291 | } |
||||
| 292 | |||||
| 293 | /** |
||||
| 294 | * @return Album[] |
||||
| 295 | */ |
||||
| 296 | public function findAllByGenre(int $genreId, string $userId, ?int $limit=null, ?int $offset=null) : array { |
||||
| 297 | $sql = $this->selectUserEntities('EXISTS '. |
||||
| 298 | '(SELECT 1 FROM `*PREFIX*music_tracks` `track` |
||||
| 299 | WHERE `*PREFIX*music_albums`.`id` = `track`.`album_id` |
||||
| 300 | AND `track`.`genre_id` = ?)'); |
||||
| 301 | |||||
| 302 | $params = [$userId, $genreId]; |
||||
| 303 | return $this->findEntities($sql, $params, $limit, $offset); |
||||
| 304 | } |
||||
| 305 | |||||
| 306 | /** |
||||
| 307 | * @return boolean True if one or more albums were influenced |
||||
| 308 | */ |
||||
| 309 | public function updateFolderCover(int $coverFileId, int $folderId) : bool { |
||||
| 310 | $sql = 'SELECT DISTINCT `tracks`.`album_id` |
||||
| 311 | FROM `*PREFIX*music_tracks` `tracks` |
||||
| 312 | JOIN `*PREFIX*filecache` `files` ON `tracks`.`file_id` = `files`.`fileid` |
||||
| 313 | WHERE `files`.`parent` = ?'; |
||||
| 314 | $params = [$folderId]; |
||||
| 315 | $result = $this->execute($sql, $params); |
||||
| 316 | $albumIds = $result->fetchAll(\PDO::FETCH_COLUMN); |
||||
|
0 ignored issues
–
show
The function
OCP\DB\IPreparedStatement::fetchAll() has been deprecated: 21.0.0 use \OCP\DB\IResult::fetchAll on the \OCP\DB\IResult returned by \OCP\IDBConnection::prepare
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. Loading history...
|
|||||
| 317 | $result->closeCursor(); |
||||
|
0 ignored issues
–
show
The function
OCP\DB\IPreparedStatement::closeCursor() has been deprecated: 21.0.0 use \OCP\DB\IResult::closeCursor on the \OCP\DB\IResult returned by \OCP\IDBConnection::prepare
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. Loading history...
|
|||||
| 318 | |||||
| 319 | $updated = false; |
||||
| 320 | if (\count($albumIds) > 0) { |
||||
| 321 | $sql = 'UPDATE `*PREFIX*music_albums` |
||||
| 322 | SET `cover_file_id` = ? |
||||
| 323 | WHERE `cover_file_id` IS NULL AND `id` IN '. $this->questionMarks(\count($albumIds)); |
||||
| 324 | $params = \array_merge([$coverFileId], $albumIds); |
||||
| 325 | $result = $this->execute($sql, $params); |
||||
| 326 | $updated = $result->rowCount() > 0; |
||||
|
0 ignored issues
–
show
The function
OCP\DB\IPreparedStatement::rowCount() has been deprecated: 21.0.0 use \OCP\DB\IResult::rowCount on the \OCP\DB\IResult returned by \OCP\IDBConnection::prepare
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. Loading history...
|
|||||
| 327 | $result->closeCursor(); |
||||
|
0 ignored issues
–
show
The function
OCP\DB\IPreparedStatement::closeCursor() has been deprecated: 21.0.0 use \OCP\DB\IResult::closeCursor on the \OCP\DB\IResult returned by \OCP\IDBConnection::prepare
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. Loading history...
|
|||||
| 328 | } |
||||
| 329 | |||||
| 330 | return $updated; |
||||
| 331 | } |
||||
| 332 | |||||
| 333 | /** |
||||
| 334 | * Set file ID to be used as cover for an album |
||||
| 335 | */ |
||||
| 336 | public function setCover(?int $coverFileId, int $albumId) : void { |
||||
| 337 | $sql = 'UPDATE `*PREFIX*music_albums` |
||||
| 338 | SET `cover_file_id` = ? |
||||
| 339 | WHERE `id` = ?'; |
||||
| 340 | $params = [$coverFileId, $albumId]; |
||||
| 341 | $result = $this->execute($sql, $params); |
||||
| 342 | $result->closeCursor(); |
||||
|
0 ignored issues
–
show
The function
OCP\DB\IPreparedStatement::closeCursor() has been deprecated: 21.0.0 use \OCP\DB\IResult::closeCursor on the \OCP\DB\IResult returned by \OCP\IDBConnection::prepare
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. Loading history...
|
|||||
| 343 | } |
||||
| 344 | |||||
| 345 | /** |
||||
| 346 | * @param integer[] $coverFileIds |
||||
| 347 | * @param string[]|null $userIds the users whose music library is targeted; all users are targeted if omitted |
||||
| 348 | * @return Album[] albums which got modified (with incomplete data, only id and user are valid), |
||||
| 349 | * empty array if none |
||||
| 350 | */ |
||||
| 351 | public function removeCovers(array $coverFileIds, ?array $userIds=null) : array { |
||||
| 352 | // find albums using the given file as cover |
||||
| 353 | $sql = 'SELECT `id`, `user_id` FROM `*PREFIX*music_albums` WHERE `cover_file_id` IN ' . |
||||
| 354 | $this->questionMarks(\count($coverFileIds)); |
||||
| 355 | $params = $coverFileIds; |
||||
| 356 | if ($userIds !== null) { |
||||
| 357 | $sql .= ' AND `user_id` IN ' . $this->questionMarks(\count($userIds)); |
||||
| 358 | $params = \array_merge($params, $userIds); |
||||
| 359 | } |
||||
| 360 | $albums = $this->findEntities($sql, $params); |
||||
| 361 | |||||
| 362 | // if any albums found, remove the cover from those |
||||
| 363 | $count = \count($albums); |
||||
| 364 | if ($count) { |
||||
| 365 | $sql = 'UPDATE `*PREFIX*music_albums` |
||||
| 366 | SET `cover_file_id` = NULL |
||||
| 367 | WHERE `id` IN ' . $this->questionMarks($count); |
||||
| 368 | $params = ArrayUtil::extractIds($albums); |
||||
| 369 | $result = $this->execute($sql, $params); |
||||
| 370 | $result->closeCursor(); |
||||
|
0 ignored issues
–
show
The function
OCP\DB\IPreparedStatement::closeCursor() has been deprecated: 21.0.0 use \OCP\DB\IResult::closeCursor on the \OCP\DB\IResult returned by \OCP\IDBConnection::prepare
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. Loading history...
|
|||||
| 371 | } |
||||
| 372 | |||||
| 373 | return $albums; |
||||
| 374 | } |
||||
| 375 | |||||
| 376 | /** |
||||
| 377 | * @param string|null $userId target user; omit to target all users |
||||
| 378 | * @param ?int[] $parentIds limit search to albums having tracks in these folders; omit for no limit |
||||
| 379 | * @return array<array{albumId: int, userId: string, parentFolderId: int}> |
||||
| 380 | */ |
||||
| 381 | public function getAlbumsWithoutCover(?string $userId = null, ?array $parentIds = null) : array { |
||||
| 382 | $sql = 'SELECT DISTINCT `albums`.`id`, `albums`.`user_id`, `files`.`parent` |
||||
| 383 | FROM `*PREFIX*music_albums` `albums` |
||||
| 384 | JOIN `*PREFIX*music_tracks` `tracks` ON `albums`.`id` = `tracks`.`album_id` |
||||
| 385 | JOIN `*PREFIX*filecache` `files` ON `tracks`.`file_id` = `files`.`fileid` |
||||
| 386 | WHERE `albums`.`cover_file_id` IS NULL'; |
||||
| 387 | $params = []; |
||||
| 388 | if ($userId !== null) { |
||||
| 389 | $sql .= ' AND `albums`.`user_id` = ?'; |
||||
| 390 | $params[] = $userId; |
||||
| 391 | } |
||||
| 392 | if (!empty($parentIds)) { |
||||
| 393 | $sql .= ' AND `files`.`parent` IN ' . $this->questionMarks(\count($parentIds)); |
||||
| 394 | $params = \array_merge($params, $parentIds); |
||||
| 395 | } |
||||
| 396 | |||||
| 397 | $result = $this->execute($sql, $params); |
||||
| 398 | $return = []; |
||||
| 399 | while ($row = $result->fetch()) { |
||||
|
0 ignored issues
–
show
The function
OCP\DB\IPreparedStatement::fetch() has been deprecated: 21.0.0 use \OCP\DB\IResult::fetch on the \OCP\DB\IResult returned by \OCP\IDBConnection::prepare
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. Loading history...
|
|||||
| 400 | $return[] = [ |
||||
| 401 | 'albumId' => (int)$row['id'], |
||||
| 402 | 'userId' => $row['user_id'], |
||||
| 403 | 'parentFolderId' => (int)$row['parent'] |
||||
| 404 | ]; |
||||
| 405 | } |
||||
| 406 | $result->closeCursor(); |
||||
|
0 ignored issues
–
show
The function
OCP\DB\IPreparedStatement::closeCursor() has been deprecated: 21.0.0 use \OCP\DB\IResult::closeCursor on the \OCP\DB\IResult returned by \OCP\IDBConnection::prepare
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. Loading history...
|
|||||
| 407 | |||||
| 408 | return $return; |
||||
| 409 | } |
||||
| 410 | |||||
| 411 | /** |
||||
| 412 | * @return boolean True if a cover image was found and added for the album |
||||
| 413 | */ |
||||
| 414 | public function findAlbumCover(int $albumId, int $parentFolderId) : bool { |
||||
| 415 | $return = false; |
||||
| 416 | $imagesSql = 'SELECT `fileid`, `name` |
||||
| 417 | FROM `*PREFIX*filecache` |
||||
| 418 | JOIN `*PREFIX*mimetypes` ON `*PREFIX*mimetypes`.`id` = `*PREFIX*filecache`.`mimetype` |
||||
| 419 | WHERE `parent` = ? AND `*PREFIX*mimetypes`.`mimetype` LIKE \'image%\''; |
||||
| 420 | $params = [$parentFolderId]; |
||||
| 421 | $result = $this->execute($imagesSql, $params); |
||||
| 422 | $images = $result->fetchAll(); |
||||
|
0 ignored issues
–
show
The function
OCP\DB\IPreparedStatement::fetchAll() has been deprecated: 21.0.0 use \OCP\DB\IResult::fetchAll on the \OCP\DB\IResult returned by \OCP\IDBConnection::prepare
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. Loading history...
|
|||||
| 423 | $result->closeCursor(); |
||||
|
0 ignored issues
–
show
The function
OCP\DB\IPreparedStatement::closeCursor() has been deprecated: 21.0.0 use \OCP\DB\IResult::closeCursor on the \OCP\DB\IResult returned by \OCP\IDBConnection::prepare
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. Loading history...
|
|||||
| 424 | if (\count($images) > 0) { |
||||
| 425 | $getImageRank = function($imageName) { |
||||
| 426 | $coverNames = ['cover', 'albumart', 'album', 'front', 'folder']; |
||||
| 427 | foreach ($coverNames as $i => $coverName) { |
||||
| 428 | if (StringUtil::startsWith($imageName, $coverName, /*$ignoreCase=*/true)) { |
||||
| 429 | return $i; |
||||
| 430 | } |
||||
| 431 | } |
||||
| 432 | return \count($coverNames); |
||||
| 433 | }; |
||||
| 434 | |||||
| 435 | \usort($images, fn($imageA, $imageB) => |
||||
| 436 | $getImageRank($imageA['name']) <=> $getImageRank($imageB['name']) |
||||
| 437 | ); |
||||
| 438 | $imageId = (int)$images[0]['fileid']; |
||||
| 439 | $this->setCover($imageId, $albumId); |
||||
| 440 | $return = true; |
||||
| 441 | } |
||||
| 442 | return $return; |
||||
| 443 | } |
||||
| 444 | |||||
| 445 | /** |
||||
| 446 | * Given an array of track IDs, find corresponding unique album IDs, including only |
||||
| 447 | * those album which have a cover art set. |
||||
| 448 | * @param int[] $trackIds |
||||
| 449 | * @return Album[] |
||||
| 450 | */ |
||||
| 451 | public function findAlbumsWithCoversForTracks(array $trackIds, string $userId, int $limit) : array { |
||||
| 452 | $sql = 'SELECT DISTINCT `albums`.* |
||||
| 453 | FROM `*PREFIX*music_albums` `albums` |
||||
| 454 | JOIN `*PREFIX*music_tracks` `tracks` ON `albums`.`id` = `tracks`.`album_id` |
||||
| 455 | WHERE `albums`.`cover_file_id` IS NOT NULL |
||||
| 456 | AND `albums`.`user_id` = ? |
||||
| 457 | AND `tracks`.`id` IN ' . $this->questionMarks(\count($trackIds)); |
||||
| 458 | $params = \array_merge([$userId], $trackIds); |
||||
| 459 | |||||
| 460 | return $this->findEntities($sql, $params, $limit); |
||||
| 461 | } |
||||
| 462 | |||||
| 463 | /** |
||||
| 464 | * Returns the count of albums where the given Artist is featured in |
||||
| 465 | * @param integer $artistId |
||||
| 466 | * @return integer |
||||
| 467 | */ |
||||
| 468 | public function countByArtist(int $artistId) : int { |
||||
| 469 | $sql = 'SELECT COUNT(*) AS count FROM ( |
||||
| 470 | SELECT DISTINCT `track`.`album_id` |
||||
| 471 | FROM `*PREFIX*music_tracks` `track` |
||||
| 472 | WHERE `track`.`artist_id` = ? |
||||
| 473 | UNION |
||||
| 474 | SELECT `album`.`id` |
||||
| 475 | FROM `*PREFIX*music_albums` `album` |
||||
| 476 | WHERE `album`.`album_artist_id` = ? |
||||
| 477 | ) tmp'; |
||||
| 478 | $params = [$artistId, $artistId]; |
||||
| 479 | $result = $this->execute($sql, $params); |
||||
| 480 | $row = $result->fetch(); |
||||
|
0 ignored issues
–
show
The function
OCP\DB\IPreparedStatement::fetch() has been deprecated: 21.0.0 use \OCP\DB\IResult::fetch on the \OCP\DB\IResult returned by \OCP\IDBConnection::prepare
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. Loading history...
|
|||||
| 481 | $result->closeCursor(); |
||||
|
0 ignored issues
–
show
The function
OCP\DB\IPreparedStatement::closeCursor() has been deprecated: 21.0.0 use \OCP\DB\IResult::closeCursor on the \OCP\DB\IResult returned by \OCP\IDBConnection::prepare
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. Loading history...
|
|||||
| 482 | return (int)$row['count']; |
||||
| 483 | } |
||||
| 484 | |||||
| 485 | /** |
||||
| 486 | * Returns the count of albums where the given artist is the album artist |
||||
| 487 | * @param integer $artistId |
||||
| 488 | * @return integer |
||||
| 489 | */ |
||||
| 490 | public function countByAlbumArtist(int $artistId) : int { |
||||
| 491 | $sql = 'SELECT COUNT(*) AS count |
||||
| 492 | FROM `*PREFIX*music_albums` `album` |
||||
| 493 | WHERE `album`.`album_artist_id` = ?'; |
||||
| 494 | $params = [$artistId]; |
||||
| 495 | $result = $this->execute($sql, $params); |
||||
| 496 | $row = $result->fetch(); |
||||
|
0 ignored issues
–
show
The function
OCP\DB\IPreparedStatement::fetch() has been deprecated: 21.0.0 use \OCP\DB\IResult::fetch on the \OCP\DB\IResult returned by \OCP\IDBConnection::prepare
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. Loading history...
|
|||||
| 497 | $result->closeCursor(); |
||||
|
0 ignored issues
–
show
The function
OCP\DB\IPreparedStatement::closeCursor() has been deprecated: 21.0.0 use \OCP\DB\IResult::closeCursor on the \OCP\DB\IResult returned by \OCP\IDBConnection::prepare
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead. Loading history...
|
|||||
| 498 | return (int)$row['count']; |
||||
| 499 | } |
||||
| 500 | |||||
| 501 | /** |
||||
| 502 | * Overridden from the base implementation to provide support for table-specific rules |
||||
| 503 | * |
||||
| 504 | * {@inheritdoc} |
||||
| 505 | * @see BaseMapper::advFormatSqlCondition() |
||||
| 506 | */ |
||||
| 507 | protected function advFormatSqlCondition(string $rule, string $sqlOp, string $conv) : string { |
||||
| 508 | // The extra subquery "mysqlhack" seen around some nested queries is needed in order for these to not be insanely slow on MySQL. |
||||
| 509 | // In case of 'recent_played', the MySQL 5.5.62 errored with "1235 This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'" without the extra subquery. |
||||
| 510 | $condForRule = [ |
||||
| 511 | 'album_artist' => "$conv(`artist`.`name`) $sqlOp $conv(?)", |
||||
| 512 | 'song_artist' => "`*PREFIX*music_albums`.`id` IN (SELECT `album_id` FROM `*PREFIX*music_tracks` `t` JOIN `*PREFIX*music_artists` `ar` ON `t`.`artist_id` = `ar`.`id` WHERE $conv(`ar`.`name`) $sqlOp $conv(?))", |
||||
| 513 | 'song' => "`*PREFIX*music_albums`.`id` IN (SELECT `album_id` FROM `*PREFIX*music_tracks` `t` WHERE $conv(`t`.`title`) $sqlOp $conv(?))", |
||||
| 514 | 'original_year' => "`*PREFIX*music_albums`.`id` IN (SELECT * FROM (SELECT `album_id` FROM `*PREFIX*music_tracks` GROUP BY `album_id` HAVING MIN(`year`) $sqlOp ?) mysqlhack)", |
||||
| 515 | 'songrating' => "`*PREFIX*music_albums`.`id` IN (SELECT `album_id` FROM `*PREFIX*music_tracks` `t` WHERE `t`.`rating` $sqlOp ?)", |
||||
| 516 | 'artistrating' => "`artist`.rating $sqlOp ?", |
||||
| 517 | 'played_times' => "`*PREFIX*music_albums`.`id` IN (SELECT * FROM (SELECT `album_id` from `*PREFIX*music_tracks` GROUP BY `album_id` HAVING SUM(`play_count`) $sqlOp ?) mysqlhack)", |
||||
| 518 | 'last_play' => "`*PREFIX*music_albums`.`id` IN (SELECT * FROM (SELECT `album_id` from `*PREFIX*music_tracks` GROUP BY `album_id` HAVING MAX(`last_played`) $sqlOp ?) mysqlhack)", |
||||
| 519 | 'myplayed' => "`*PREFIX*music_albums`.`id` IN (SELECT * FROM (SELECT `album_id` from `*PREFIX*music_tracks` GROUP BY `album_id` HAVING MAX(`last_played`) $sqlOp) mysqlhack)", // operator "IS NULL" or "IS NOT NULL" |
||||
| 520 | 'myplayedartist'=> "`album_artist_id` IN (SELECT * FROM (SELECT `artist_id` from `*PREFIX*music_tracks` GROUP BY `artist_id` HAVING MAX(`last_played`) $sqlOp) mysqlhack)", // operator "IS NULL" or "IS NOT NULL" |
||||
| 521 | 'song_count' => "`*PREFIX*music_albums`.`id` IN (SELECT * FROM (SELECT `album_id` FROM `*PREFIX*music_tracks` GROUP BY `album_id` HAVING COUNT(`id`) $sqlOp ?) mysqlhack)", |
||||
| 522 | 'disk_count' => "`*PREFIX*music_albums`.`id` IN (SELECT * FROM (SELECT `album_id` FROM `*PREFIX*music_tracks` GROUP BY `album_id` HAVING MAX(`disk`) $sqlOp ?) mysqlhack)", |
||||
| 523 | 'time' => "`*PREFIX*music_albums`.`id` IN (SELECT * FROM (SELECT `album_id` FROM `*PREFIX*music_tracks` GROUP BY `album_id` HAVING SUM(`length`) $sqlOp ?) mysqlhack)", |
||||
| 524 | 'album_genre' => "`*PREFIX*music_albums`.`id` IN (SELECT * FROM (SELECT `album_id` FROM `*PREFIX*music_tracks` `t` JOIN `*PREFIX*music_genres` `g` ON `t`.`genre_id` = `g`.`id` GROUP BY `album_id` HAVING $conv(" . $this->sqlGroupConcat('`g`.`name`') . ") $sqlOp $conv(?)) mysqlhack)", |
||||
| 525 | 'song_genre' => "`*PREFIX*music_albums`.`id` IN (SELECT `album_id` FROM `*PREFIX*music_tracks` `t` JOIN `*PREFIX*music_genres` `g` ON `t`.`genre_id` = `g`.`id` WHERE $conv(`g`.`name`) $sqlOp $conv(?))", |
||||
| 526 | 'no_genre' => "`*PREFIX*music_albums`.`id` IN (SELECT `album_id` FROM `*PREFIX*music_tracks` `t` JOIN `*PREFIX*music_genres` `g` ON `t`.`genre_id` = `g`.`id` WHERE `g`.`name` " . (($sqlOp == 'IS NOT NULL') ? '=' : '!=') . ' "")', |
||||
| 527 | 'playlist' => "`*PREFIX*music_albums`.`id` IN (SELECT `album_id` FROM `*PREFIX*music_tracks` `t` WHERE $sqlOp EXISTS (SELECT 1 from `*PREFIX*music_playlists` `p` WHERE `p`.`id` = ? AND `p`.`track_ids` LIKE " . $this->sqlConcat("'%|'", "`t`.`id`", "'|%'") . '))', |
||||
| 528 | 'playlist_name' => "`*PREFIX*music_albums`.`id` IN (SELECT `album_id` FROM `*PREFIX*music_tracks` `t` WHERE EXISTS (SELECT 1 from `*PREFIX*music_playlists` `p` WHERE $conv(`p`.`name`) $sqlOp $conv(?) AND `p`.`track_ids` LIKE " . $this->sqlConcat("'%|'", "`t`.`id`", "'|%'") . '))', |
||||
| 529 | 'file' => "`*PREFIX*music_albums`.`id` IN (SELECT `album_id` FROM `*PREFIX*music_tracks` `t` JOIN `*PREFIX*filecache` `f` ON `t`.`file_id` = `f`.`fileid` WHERE $conv(`f`.`name`) $sqlOp $conv(?))", |
||||
| 530 | 'recent_played' => "`*PREFIX*music_albums`.`id` IN (SELECT `album_id` FROM (SELECT `album_id`, MAX(`last_played`) FROM `*PREFIX*music_tracks` WHERE `user_id` = ? GROUP BY `album_id` ORDER BY MAX(`last_played`) DESC LIMIT $sqlOp) mysqlhack)", |
||||
| 531 | 'mbid_song' => "`*PREFIX*music_albums`.`id` IN (SELECT `album_id` FROM `*PREFIX*music_tracks` `t` WHERE `t`.`mbid` $sqlOp ?)", |
||||
| 532 | 'mbid_artist' => "`artist`.`mbid` $sqlOp ?", |
||||
| 533 | 'has_image' => "`*PREFIX*music_albums`.`cover_file_id` $sqlOp" // operator "IS NULL" or "IS NOT NULL" |
||||
| 534 | ]; |
||||
| 535 | |||||
| 536 | // Add alias rules |
||||
| 537 | $condForRule['year'] = $condForRule['original_year']; // we only have one kind of year |
||||
| 538 | $condForRule['played'] = $condForRule['myplayed']; // we give no access to other people's data; not part of the API spec but Ample uses this |
||||
| 539 | $condForRule['artist'] = $condForRule['album_artist']; |
||||
| 540 | $condForRule['genre'] = $condForRule['album_genre']; |
||||
| 541 | $condForRule['album'] = parent::advFormatSqlCondition('title', $sqlOp, $conv); |
||||
| 542 | $condForRule['mbid_album'] = parent::advFormatSqlCondition('mbid', $sqlOp, $conv); |
||||
| 543 | |||||
| 544 | return $condForRule[$rule] ?? parent::advFormatSqlCondition($rule, $sqlOp, $conv); |
||||
| 545 | } |
||||
| 546 | } |
||||
| 547 |