diff --git a/src/Entity/Repository/StationQueueRepository.php b/src/Entity/Repository/StationQueueRepository.php index 59061ad0f..81a6382f8 100644 --- a/src/Entity/Repository/StationQueueRepository.php +++ b/src/Entity/Repository/StationQueueRepository.php @@ -68,42 +68,28 @@ final class StationQueueRepository extends AbstractStationBasedRepository ->execute(); } - /** - * @return int[] - */ - public function getRecentPlaylists( - Entity\Station $station, - int $rows - ): array { - /* - * Explanation for why this is done in two queries: - * MariaDB won't apply indices if you order by one field ASC, then another DESC. - * The combiend query would order by is_played ASC, then timestamp_played DESC. - * This forces the use of indices at the expense of slightly more records being handled. - */ - $baseQueryBuilder = $this->em->createQueryBuilder() - ->select('sq.timestamp_played, sq.is_visible, sq.playlist_id') - ->from(Entity\StationQueue::class, 'sq') - ->where('sq.station = :station') - ->setParameter('station', $station) - ->orderBy('sq.timestamp_played', 'DESC'); + public function isPlaylistRecentlyPlayed( + Entity\StationPlaylist $playlist, + ?int $playPerSongs = null + ): bool { + $playPerSongs ??= $playlist->getPlayPerSongs(); - $unplayedRows = (clone $baseQueryBuilder) - ->andWhere('sq.is_played = 0') - ->getQuery() - ->getArrayResult(); + $recentPlayedQuery = $this->em->createQuery( + <<<'DQL' + SELECT sq.playlist_id + FROM App\Entity\StationQueue sq + WHERE sq.station = :station + AND sq.playlist_id IS NOT NULL + AND (sq.playlist = :playlist OR sq.is_visible = 1) + ORDER BY sq.id DESC + DQL + )->setParameters([ + 'station' => $playlist->getStation(), + 'playlist' => $playlist, + ])->setMaxResults($playPerSongs); - $playedRows = (clone $baseQueryBuilder) - ->andWhere('sq.is_played = 1') - ->getQuery() - ->setMaxResults($rows) - ->getArrayResult(); - - return array_slice( - array_merge($unplayedRows, $playedRows), - 0, - $rows - ); + $recentPlayedPlaylists = $recentPlayedQuery->getSingleColumnResult(); + return in_array($playlist->getIdRequired(), (array)$recentPlayedPlaylists, true); } /** diff --git a/src/Radio/AutoDJ/QueueBuilder.php b/src/Radio/AutoDJ/QueueBuilder.php index 876fedc87..21cfbb8a3 100644 --- a/src/Radio/AutoDJ/QueueBuilder.php +++ b/src/Radio/AutoDJ/QueueBuilder.php @@ -56,17 +56,11 @@ final class QueueBuilder implements EventSubscriberInterface $expectedPlayTime = $event->getExpectedPlayTime(); $activePlaylistsByType = []; - $oncePerXSongHistoryCount = 15; - foreach ($station->getPlaylists() as $playlist) { /** @var Entity\StationPlaylist $playlist */ if ($playlist->isPlayable($event->isInterrupting())) { $type = $playlist->getType(); - if (Entity\Enums\PlaylistTypes::OncePerXSongs === $playlist->getTypeEnum()) { - $oncePerXSongHistoryCount = max($oncePerXSongHistoryCount, $playlist->getPlayPerSongs()); - } - $subType = ($playlist->getScheduleItems()->count() > 0) ? 'scheduled' : 'unscheduled'; $activePlaylistsByType[$type . '_' . $subType][$playlist->getId()] = $playlist; } @@ -77,11 +71,6 @@ final class QueueBuilder implements EventSubscriberInterface return; } - $recentPlaylistHistory = $this->queueRepo->getRecentPlaylists( - $station, - $oncePerXSongHistoryCount - ); - $recentSongHistoryForDuplicatePrevention = $this->queueRepo->getRecentlyPlayedByTimeRange( $station, $expectedPlayTime, @@ -91,7 +80,6 @@ final class QueueBuilder implements EventSubscriberInterface $this->logger->debug( 'AutoDJ recent song playback history', [ - 'history_once_per_x_songs' => $recentPlaylistHistory, 'history_duplicate_prevention' => $recentSongHistoryForDuplicatePrevention, ] ); @@ -117,7 +105,7 @@ final class QueueBuilder implements EventSubscriberInterface $logPlaylists = []; foreach ($activePlaylistsByType[$currentPlaylistType] as $playlistId => $playlist) { /** @var Entity\StationPlaylist $playlist */ - if (!$this->scheduler->shouldPlaylistPlayNow($playlist, $expectedPlayTime, $recentPlaylistHistory)) { + if (!$this->scheduler->shouldPlaylistPlayNow($playlist, $expectedPlayTime)) { continue; } diff --git a/src/Radio/AutoDJ/Scheduler.php b/src/Radio/AutoDJ/Scheduler.php index e1ce62e49..55a9e9f5c 100644 --- a/src/Radio/AutoDJ/Scheduler.php +++ b/src/Radio/AutoDJ/Scheduler.php @@ -27,8 +27,7 @@ final class Scheduler public function shouldPlaylistPlayNow( Entity\StationPlaylist $playlist, - CarbonInterface $now = null, - array $recentPlaylistHistory = [] + CarbonInterface $now = null ): bool { $this->logger->pushProcessor( function (LogRecord $record) use ($playlist) { @@ -66,7 +65,7 @@ final class Scheduler case Entity\Enums\PlaylistTypes::OncePerXSongs: $playPerSongs = $playlist->getPlayPerSongs(); - $shouldPlay = !$this->wasPlaylistPlayedRecently($playlist, $recentPlaylistHistory, $playPerSongs); + $shouldPlay = !$this->queueRepo->isPlaylistRecentlyPlayed($playlist, $playPerSongs); $this->logger->debug( sprintf( @@ -154,40 +153,6 @@ final class Scheduler return ($playedAt > $threshold); } - private function wasPlaylistPlayedRecently( - Entity\StationPlaylist $playlist, - array $recentPlaylistHistory = [], - int $length = 15 - ): bool { - if (empty($recentPlaylistHistory)) { - return false; - } - - $playlistId = $playlist->getIdRequired(); - - // Only consider playlists that are this playlist or are non-jingles. - $relevantSongHistory = array_slice( - array_filter( - $recentPlaylistHistory, - static function ($row) use ($playlistId) { - return $playlistId === $row['playlist_id'] - ? true - : $row['is_visible']; - } - ), - 0, - $length - ); - - foreach ($relevantSongHistory as $sh_row) { - if ($playlistId === (int)$sh_row['playlist_id']) { - return true; - } - } - - return false; - } - /** * Get the duration of scheduled play time in seconds (used for remote URLs of indeterminate length). *