Skip to content

Instantly share code, notes, and snippets.

@nathanlesage
Last active November 17, 2023 14:09
Show Gist options
  • Save nathanlesage/4033664c1e5cd2471e7b7d15a3bcf90d to your computer and use it in GitHub Desktop.
Save nathanlesage/4033664c1e5cd2471e7b7d15a3bcf90d to your computer and use it in GitHub Desktop.
This PHP file simply requires an online web server and some variables by you and it will show you the overall statistics of your repository.
<?php
/*
* GitHub Download Counter page
* Created by Hendrik Erz <[email protected]>
* Licensed via GNU GPL v3
*/
// CONFIG
$repo = 'Zettlr/Zettlr'; // The repository
$highlight = '#3e6dd6'; // The highlight color for the page.
// Calculate a few things
$is_light = hexdec(substr($highlight, 1)) > 0xffffff * 0.5;
$contrast_strong = ($is_light) ? '#000' : '#fff';
$contrast_soft = ($is_light) ? '#444' : '#ddd';
// HELPER FUNCTIONS
function cURL ($url) {
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT,1);
// GitHub requires a user agent header. So we'll just take something.
curl_setopt($ch, CURLOPT_HTTPHEADER, array("User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.89 Safari/537.36"));
$result = curl_exec($ch);
curl_close($ch);
return $result;
}
function retrieveReleases ($repo) {
$today = date('Y-m-d');
$cache_file = "cache_$today.json";
if (file_exists($cache_file)) {
$cache = file_get_contents($cache_file);
if ($cache !== false) {
// Return the cache
return json_decode($cache);
}
} else {
// We will create the cache later on -- remove other cache files
$files = scandir('.');
if ($files !== false) {
foreach ($files as $file) {
if (preg_match('/cache_\d{4}-\d{2}-\d{2}\.json/', $file) === 1) {
unlink($file);
}
}
}
}
// First, let's grab some information on the repo!
$curl_result = cURL("https://api.github.com/repos/" . $repo);
if ($curl_result === false) {
return false;
}
$repo_info = json_decode($curl_result);
// Next on: The repo itself. NOTE: We will simply create a new array key for
// the releases.
// We have to account for the Github v3 pagination, which limits output to
// 30 entries.
$repo_info->all_releases = [];
$page = 0;
do {
$page++;
$releases = cURL("https://api.github.com/repos/" . $repo . "/releases?page=" . $page);
if ($releases === false) {
return false;
}
$releases = json_decode($releases);
$repo_info->all_releases = array_merge($repo_info->all_releases, $releases);
} while (sizeof($releases) > 0);
// Cache the result
$cache_contents = json_encode($repo_info);
file_put_contents($cache_file, $cache_contents);
// Return the cache
return $repo_info;
}
// Helper function for delimiting numbers over 1.000 in output
function localise_number ($number) {
if ($number < 1000) {
return $number;
}
$delim = ',';
$ret = (string) $number;
$cnt = 0;
for ($i = strlen($ret) - 1; $i > 0; $i--) {
$cnt++;
if ($cnt === 3) {
$ret = substr($ret, 0, $i) . $delim . substr($ret, $i);
$cnt = 0;
}
}
return $ret;
}
function isWindowsExe ($filename) {
return (
str_ends_with($filename, '.exe') ||
str_ends_with($filename, '.msi')
);
}
function isMacOSApp ($filename) {
return (
str_ends_with($filename, '.dmg') ||
str_ends_with($filename, '.pkg')
);
}
function isLinuxExec ($filename) {
return (
str_ends_with($filename, '.deb') ||
str_ends_with($filename, '.rpm') ||
str_ends_with($filename, '.AppImage')
);
}
function totalDownloadsPerPlatform ($releases) {
$release_count = [
'Windows' => 0,
'macOS' => 0,
'Linux' => 0,
'Other Files' => 0,
];
foreach($releases as $release) {
foreach($release->assets as $asset) {
if (isWindowsExe($asset->name)) {
$release_count['Windows'] += $asset->download_count;
} else if (isMacOSApp($asset->name)) {
$release_count['macOS'] += $asset->download_count;
} else if (isLinuxExec($asset->name)) {
$release_count['Linux'] += $asset->download_count;
} else {
$release_count['Other Files'] += $asset->download_count;
}
}
}
return $release_count;
}
function readableKB ($kb) {
$ret_val = $kb;
$unit = 'KB';
if ($ret_val > 1000) {
$ret_val /= 1000;
$unit = 'MB';
}
if ($ret_val > 1000) {
$ret_val /= 1000;
$unit = 'GB';
}
if ($ret_val > 1000) {
$ret_val /= 1000;
$unit = 'TB';
}
$ret_val = round($ret_val, 2);
return "$ret_val $unit";
}
// Now, actually retrieve the releases
$repo_info = retrieveReleases($repo);
$downloads = totalDownloadsPerPlatform($repo_info->all_releases);
?>
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title><?php echo $repo_info->name; ?> Download Count</title>
<style type="text/css">
* {
box-sizing:border-box;
}
html, body {
margin:0;
padding:0;
}
body {
font-family: sans-serif;
cursor:default;
}
h1, p {
margin:0.5em;
line-height: 120%;
}
a, a:visited, a:focus {
color: <?php echo $highlight; ?>;
text-decoration: none;
transition:0.5s color ease;
}
a:hover {
color: #999;
transition:0.5s color ease;
}
footer {
position: fixed;
width: 100%;
bottom: 0;
background-color: <?php echo $highlight; ?>;
color: <?php echo $contrast_strong; ?>;
display: block;
line-height: 200%;
text-align: center;
}
footer a {
color: <?php echo $contrast_soft; ?> !important;
}
div.container {
width:100%;
}
@media (min-width:600px) { div.container { width: 80%; margin:0 auto; } }
@media (min-width:800px) { div.container { width: 60%; margin:0 auto; } }
@media (min-width:1000px) { div.container { width: 50%; margin:0 auto; } }
@media (min-width:1200px) { div.container { width: 40%; margin:0 auto; } }
table {
border-collapse: collapse;
width: 100%;
}
th, td {
padding: 4px 20px;
border-bottom: 1px solid #333;
}
td.number {
text-align: right;
padding-right: 20px;
}
td.filename {
font-size: 80%;
color: <?php echo $highlight; ?>;
}
td.divider {
background-color: <?php echo $highlight; ?>;
opacity: 0.2;
border: none;
border-bottom: 1px solid white;
border-bottom-left-radius: 10px;
border-bottom-right-radius: 10px;
}
tr {
border-bottom: 1px solid #333;
}
tr:hover {
background-color: #ddd;
}
span.date {
font-style: italic;
font-weight: normal;
font-size: 75%;
}
a.topic-button {
display: inline-block;
margin: 5px;
padding: 5px 10px;
border-radius: 4px;
background-color: <?php echo $highlight; ?>;
color: <?php echo $contrast_strong; ?>;
opacity: 0.8;
}
a.topic-button:hover {
opacity: 1;
}
div#card-container {
display: flex;
}
div.card {
flex: 1 1 0px;
padding: 10px;
margin: 0 10px;
border-radius: 10px;
background-color: <?php echo $highlight; ?>;
color: <?php echo $contrast_strong; ?>;
text-align: center;
font-weight: bold;
}
hr {
margin: 20px 0px;
}
</style>
</head>
<body>
<div class="container">
<h1><?php echo $repo_info->name; ?> Download Count</h1>
<p><em><?php echo $repo_info->description; ?></em> | <a href="<?php echo $repo_info->html_url; ?>" target="_blank">GitHub</a></p>
<p>This page shows overall download counts for all versions of <?php echo $repo_info->name; ?>.</p>
<div id="card-container">
<div class="card">
<p>Stargazers</p>
<p><?php echo localise_number($repo_info->stargazers_count); ?></p>
</div>
<div class="card">
<p>Forks</p>
<p><?php echo localise_number($repo_info->forks_count); ?></p>
</div>
<div class="card">
<p>Issues</p>
<p><?php echo localise_number($repo_info->open_issues_count); ?></p>
</div>
<div class="card">
<p>Repository Size</p>
<p><?php echo readableKB($repo_info->size); ?></p>
</div>
</div>
<hr>
<p>
<?php
foreach ($repo_info->topics as $topic) {
echo "<a href=\"https://github.com/topics/$topic\" class=\"topic-button\" target=\"_blank\">$topic</a>";
}
?>
</p>
<h2>At a Glance</h2>
<p>
<table>
<thead>
<tr>
<th style="text-align: left;">Platform</th>
<th style="text-align: right;">Total Download Count</th>
</tr>
</thead>
<tbody>
<?php
$total = 0;
foreach ($downloads as $platform => $count) {
$total += $count;
echo "<tr><td>$platform</td><td class=\"number\">" . localise_number($count) . "</td></tr>";
}
echo "<tr><th style=\"text-align: left;\">Total downloads:</th><th style=\"text-align: right;\">" . localise_number($total) . "</th></tr>";
?>
</tbody>
</table>
</p>
<p>&nbsp;</p>
<?php
// Additional info: How many days since the first release?
$firstRelease = array_reverse($repo_info->all_releases)[0]; // Last index = first release
// Get Unix seconds
$firstRelease = strtotime($firstRelease->published_at);
$daysSinceFirstRelease = round((time() - $firstRelease) / 60 / 60 / 24);
$yearsSinceFirstRelease = floor($daysSinceFirstRelease / 365);
$downloadsPerDay = round($total / $daysSinceFirstRelease);
echo "<p>All <strong>" . localise_number(sizeof($repo_info->all_releases)) . "</strong> releases of $repo_info->name have been downloaded <strong>" . localise_number($total) . "</strong> times.</p>\n";
echo "<p>The first release was made <strong>";
if ($yearsSinceFirstRelease > 0) {
echo "$yearsSinceFirstRelease years and " . ($daysSinceFirstRelease % 365) . " days";
} else {
echo $daysSinceFirstRelease . " days";
}
echo "</strong> ago. On average, $repo_info->name is downloaded <strong>$downloadsPerDay times each day</strong>.</p>";
?>
<p>&nbsp;</p>
<h2>In Detail</h2>
<?php
// Now generate.
echo "<table>\n<tr><th>Release</th><th style=\"text-align: left;\">Platform</th><th style=\"text-align: right;\">Downloads</th></tr>\n";
// First: Loop through all releases
foreach($repo_info->all_releases as $release) {
echo "<tr><th rowspan=\"" . (count($release->assets)+1) . "\">$release->tag_name<br><span class=\"date\">" . date("M d, Y, H:i", strtotime($release->published_at)) ."</span></th></tr>\n";
// Sort the assets
usort($release->assets, fn($a, $b) => $b->download_count - $a->download_count);
// Then loop through all assets ...
foreach($release->assets as $asset) {
echo "<tr><td title=\"$asset->name\" class=\"filename\">$asset->name</td><td class=\"number\">" . localise_number($asset->download_count) . "</td></tr>\n";
}
// Everytime add a spacer row
echo "<tr><td class=\"divider\" colspan=\"3\"></td></tr>";
}
echo "</table>\n";
?>
<div style="margin-bottom: 20%;">&nbsp;</div>
</div>
<footer>
GitHub Download Counter | Copyright &copy; 2018&mdash;<?php echo date("Y") ?> Hendrik Erz | License: <a href="https://www.gnu.org/licenses/gpl-3.0.en.html" target="_blank">GNU GPL v3</a> | <a href="https://gist.github.com/nathanlesage" target="_blank">Download at GitHub Gist</a>
</footer>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment