#6003 -- Update "play once per x songs" scheduling.
This commit is contained in:
parent
e772001fb0
commit
b16f2a94ce
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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).
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue