Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Playlists > Top Plays #453

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion css/topnav.css
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ nav .search-icon {
position: absolute;
display: block;
left: 0;
margin-right: -150px;/* TBD fix me */
margin-right: -200px;/* TBD fix me */
}
.nav-items:not(.active) li.selected ul li {
float: left;
Expand Down
6 changes: 6 additions & 0 deletions css/zoostyle.css
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,9 @@ a:hover {
.playlistHdr {
border-bottom: 1px solid gray;
}
.playlistHdr th {
text-align: left;
}
.playlistHdr td {
min-width: 30px;
}
Expand Down Expand Up @@ -858,6 +861,9 @@ li.ui-menu-item .ui-state-active,
font-size: 14px;
padding: 6px;
}
h2 .ui-selectmenu-button.ui-button {
font-size: inherit;
}

li.ui-menu-item {
font-size: 16px;
Expand Down
4 changes: 2 additions & 2 deletions engine/IPlaylist.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Zookeeper Online
*
* @author Jim Mason <[email protected]>
* @copyright Copyright (C) 1997-2023 Jim Mason <[email protected]>
* @copyright Copyright (C) 1997-2024 Jim Mason <[email protected]>
* @link https://zookeeper.ibinx.com/
* @license GPL-3.0
*
Expand Down Expand Up @@ -98,7 +98,7 @@ function updateTrack($playlistId, $id, $tag, $artist, $track, $album, $label, $d
function insertTrackEntry($playlistId, PlaylistEntry $entry, &$status);
function updateTrackEntry($playlist, PlaylistEntry $entry);
function deleteTrack($id);
function getTopPlays($airname=0, $days=41, $count=10);
function getTopPlays($airname=0, $days=41, $count=10, $excludeAutomation=true, $excludeRebroadcasts=true);
function getLastPlays($tag, $count=0, $excludeAutomation=true, $excludeRebroadcasts=true);
function getRecentPlays($airname, $count);
function getPlaysBefore($timestamp, $limit);
Expand Down
56 changes: 36 additions & 20 deletions engine/impl/Playlist.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Zookeeper Online
*
* @author Jim Mason <[email protected]>
* @copyright Copyright (C) 1997-2023 Jim Mason <[email protected]>
* @copyright Copyright (C) 1997-2024 Jim Mason <[email protected]>
* @link https://zookeeper.ibinx.com/
* @license GPL-3.0
*
Expand Down Expand Up @@ -836,20 +836,36 @@ public function deleteTrack($id) {
return $success;
}

public function getTopPlays($airname=0, $days=41, $count=10) {
public function getTopPlays($airname=0, $days=41, $count=10, $excludeAutomation=true, $excludeRebroadcasts=true) {
// if constraining by airname, no need to exclude automation
$excludeAutomation &= !$airname;
$zootopia = $excludeAutomation ? $this->getZootopiaAirname() : null;
if($zootopia) {
if(!is_array($zootopia))
$zootopia = [ $zootopia ];

$zootopiaSet = str_repeat("?,", count($zootopia) - 1) . "?";
}

$over = $airname?"distinct t.list":"*";
$query = "SELECT t.tag, count($over) plays, l.showdate, IFNULL(a.artist, t.artist) artist, t.album, t.label, count(*)" .
" FROM tracks t JOIN lists l ON t.list = l.id " .
" LEFT JOIN albumvol a ON a.tag = t.tag " .
" WHERE t.artist NOT LIKE '".IPlaylist::SPECIAL_TRACK."%' AND".
" t.album <> '' AND t.label <> '' AND";
$query = "SELECT max(t.tag) tag, count($over) plays, l.showdate, IFNULL(a.artist, t.artist) artist, t.album, t.label, count(*), a.iscoll " .
"FROM tracks t JOIN lists l ON t.list = l.id " .
($zootopia ? "LEFT JOIN airnames n ON l.airname = n.id " : "") .
"LEFT JOIN albumvol a ON a.tag = t.tag " .
"WHERE t.artist NOT LIKE '".IPlaylist::SPECIAL_TRACK."%' ".
"AND t.album <> '' AND t.label <> '' " .
($excludeRebroadcasts ? "AND origin IS NULL " : "") .
($zootopia ? "AND n.airname NOT IN ($zootopiaSet) " : "") ;
if($airname)
$query .= " l.airname = ? AND";
$query .= "AND l.airname = ? ";
if($days)
$query .= " date_add(l.showdate, interval $days day) > now() ";
$query .= " GROUP BY t.album, t.label ORDER BY 2 DESC, 7 DESC, t.artist LIMIT ?";
$query .= "AND date_add(l.showdate, interval $days day) > now() ";
$query .= "GROUP BY t.album, t.label ORDER BY 2 DESC, 7 DESC, t.artist LIMIT ?";
$stmt = $this->prepare($query);
$p = 1;
if($zootopia)
foreach($zootopia as $zka)
$stmt->bindValue($p++, $zka);
if($airname)
$stmt->bindValue($p++, (int)$airname, \PDO::PARAM_INT);
$stmt->bindValue($p++, (int)$count, \PDO::PARAM_INT);
Expand Down Expand Up @@ -878,16 +894,16 @@ public function getLastPlays($tag, $count=0, $excludeAutomation=true, $excludeRe
$zootopiaSet = str_repeat("?,", count($zootopia) - 1) . "?";
}

$query = "SELECT l.id, l.showdate, l.description, a.airname," .
" count(*) plays," .
" group_concat(t.track ORDER BY t.seq DESC, t.id DESC SEPARATOR 0x1e) tracks" .
" FROM tracks t" .
" JOIN lists l ON t.list = l.id " .
" LEFT JOIN airnames a ON l.airname = a.id" .
" WHERE t.tag = ? AND l.airname IS NOT NULL" .
($excludeRebroadcasts ? " AND origin IS NULL" : "") .
($zootopia ? " AND a.airname NOT IN ($zootopiaSet)" : "") .
" GROUP BY t.tag, l.id ORDER BY l.showdate DESC, l.showtime DESC";
$query = "SELECT l.id, l.showdate, l.description, a.airname, " .
"count(*) plays, " .
"group_concat(t.track ORDER BY t.seq DESC, t.id DESC SEPARATOR 0x1e) tracks " .
"FROM tracks t " .
"JOIN lists l ON t.list = l.id " .
"LEFT JOIN airnames a ON l.airname = a.id " .
"WHERE t.tag = ? AND l.airname IS NOT NULL " .
($excludeRebroadcasts ? "AND origin IS NULL " : "") .
($zootopia ? "AND a.airname NOT IN ($zootopiaSet) " : "") .
"GROUP BY t.tag, l.id ORDER BY l.showdate DESC, l.showtime DESC";
if($count)
$query .= " LIMIT ?";
$stmt = $this->prepare($query);
Expand Down
23 changes: 21 additions & 2 deletions ui/Playlists.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* Zookeeper Online
*
* @author Jim Mason <[email protected]>
* @copyright Copyright (C) 1997-2023 Jim Mason <[email protected]>
* @copyright Copyright (C) 1997-2024 Jim Mason <[email protected]>
* @link https://zookeeper.ibinx.com/
* @license GPL-3.0
*
Expand Down Expand Up @@ -55,6 +55,7 @@ class Playlists extends MenuItem {
[ "u", "editListGetHint", 0, "listManagerGetHint" ],
[ "u", "editListEditor", 0, "emitEditor" ],
[ "a", "viewDJ", "By DJ", "emitViewDJ" ],
[ "a", "viewTop", "Top Plays", "emitTopPlays" ],
[ "u", "import", "Import", "emitImportList" ],
];

Expand Down Expand Up @@ -266,7 +267,7 @@ private function getDJAirNames() {
// make header for edit & view playlist
private function makePlaylistHeader($isEditMode) {
$editCol = $isEditMode ? "<TD />" : "";
$header = "<TR class='playlistHdr' ALIGN=LEFT>" . $editCol . "<TH WIDTH='64px'>Time</TH><TH WIDTH='25%'>" .
$header = "<TR class='playlistHdr'>" . $editCol . "<TH WIDTH='64px'>Time</TH><TH WIDTH='25%'>" .
"Artist</TH><TH WIDTH='25%'>Track</TH><TH></TH><TH>Album/Label</TH></TR>";
return $header;
}
Expand Down Expand Up @@ -1021,6 +1022,24 @@ public function emitViewDJ() {

$this->emitViewDJMain();
}

public function emitTopPlays() {
$days = min($_REQUEST['days'] ?? 7, 42);
$limit = min($_REQUEST['limit'] ?? 30, 100);

$topPlays = Engine::api(IPlaylist::class)->getTopPlays(0, $days, $limit);
Engine::api(ILibrary::class)->markAlbumsReviewed($topPlays);

foreach($topPlays as &$entry) {
if($entry['tag'] && !$entry['iscoll'])
$entry['artist'] = PlaylistEntry::swapNames($entry['artist']);
}

$this->setTemplate('airplay.html');
$this->addVar('days', $days);
$this->addVar('limit', $limit);
$this->addVar('topPlays', $topPlays);
}

public function emitViewDJMain() {
$viewAll = $this->subaction == "viewDJAll";
Expand Down
58 changes: 58 additions & 0 deletions ui/templates/default/airplay.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{% set odays = [7, 14, 30] %}
<div class='top-airplay' style='display: none'>
<form action="?" method="POST" autocomplete="off">
<input type="hidden" name="action" value="{{ app.request.action }}">
<input type="hidden" name="subaction" value="{{ app.request.subaction }}">
<input type="hidden" name="limit" value="{{ limit }}">
<h2>Top airplay for the last
<select name="days">
{% for oday in odays %}
<option value="{{ oday }}" {{~ oday == days ? " selected" }}>{{ oday }}</option>
{% endfor %}
</select>
days
</h2>
</form>
{% if topPlays | length %}
<table class='playlistTable'>
<thead>
<tr class='playlistHdr'><th></th><th>Artist</th><th></th><th>Album/Label</th></tr>
</thead>
<tbody>
{%~ for index, entry in topPlays %}
<tr class='songRow'>
<td>{{ index + 1 }}.</td>
<td>{{ entry.iscoll ? "Various Artists" : entry.artist }}</td>
<td style='width: 15px'>{{ entry.reviewed ? "<div class='albumReview'></div>" }}</td>
<td>
{%~ if entry.album | length %}
{%~ if entry.tag %}
<a class='nav' href='?action=search&amp;s=byAlbumKey&amp;n={{ entry.tag }}'>{{ entry.album }}</a>
{%~ else %}
{{ entry.album }}
{%~ endif %}
{%~ if entry.label | length %}
<span class='songLabel'> / {{ entry.label }}</span>
{%~ endif %}
{%~ endif %}
</td>
</tr>
{%~ endfor %}
</tbody>
</table>
<h3>For complete album charting, see our <a href='?action=viewChart'><b>Airplay Charts</b></a></h3>
{% else %}
<h3>No top airplay is available</h3>
{% endif %}
</div>
<script><!--
$().ready(function() {
$("div.top-airplay select").selectmenu({width: 'auto'})
.on('change selectmenuchange', function() {
this.form.submit();
})
.closest('div').css('display', 'block')
.find('select').selectmenu('widget').trigger('focus');
});
// -->
</script>
Loading