Skip to content

Instantly share code, notes, and snippets.

@Wack0 Wack0/mastostats.php
Last active Apr 19, 2017

Embed
What would you like to do?
CLI Mastodon network stats script. Uses instances.mastodon.xyz. Updates every 60 seconds.
<?php
// This class adapted from: https://www.if-not-true-then-false.com/2010/php-class-for-coloring-php-command-line-cli-scripts-output-php-output-colorizing-using-bash-shell-colors/
class Colors {
private static $foreground_colors = array(
'black'=>'0;30',
'dark_gray'=>'1;30',
'blue'=>'0;34',
'light_blue'=>'1;34',
'green'=>'0;32',
'light_green'=>'1;32',
'cyan'=>'0;36',
'light_cyan'=>'1;36',
'red'=>'0;31',
'light_red'=>'1;31',
'purple'=>'0;35',
'light_purple'=>'1;35',
'brown'=>'0;33',
'yellow'=>'1;33',
'light_gray'=>'0;37',
'white'=>'1;37'
);
private static $background_colors = array(
'black'=>'40',
'red'=>'41',
'green'=>'42',
'yellow'=>'43',
'cyan'=>'44',
'magenta'=>'45',
'light_cyan'=>'46',
'light_gray'=>'47'
);
// Returns colored string
public static function getColoredString($string, $foreground_color = null, $background_color = 'black') {
// Only colour the string if the user hasn't opted out of colour.
global $colour;
if (!$colour) return $string;
$colored_string = "";
// Check if given foreground color found
if (isset(self::$foreground_colors[$foreground_color])) {
$colored_string .= "\033[" . self::$foreground_colors[$foreground_color] . "m";
}
// Check if given background color found
if (isset(self::$background_colors[$background_color])) {
$colored_string .= "\033[" . self::$background_colors[$background_color] . "m";
}
// Add string and end coloring
$colored_string .= $string . "\033[0m";
return $colored_string;
}
// Returns all foreground color names
public static function getForegroundColors() {
return array_keys(self::$foreground_colors);
}
// Returns all background color names
public static function getBackgroundColors() {
return array_keys(self::$background_colors);
}
}
function getColoredString($string, $foreground_color = null, $background_color = 'black') {
return Colors::getColoredString($string,$foreground_color,$background_color);
}
function usage($filename) {
global $newline;
$usage = array(
'mastostats: get Mastodon network statistics from instances.mastodon.xyz, updates every 30 seconds',
'',
'Usage: '.$filename.' [more] [<topinstances>] [nocolour]',
'',
'more: Shows more statistics - ranks the top instances by statuses and connections as well as users',
'<topinstances>: Replace with a number to show the top <topinstances> number of instances. Defaults to 10.',
'nocolour: (or \'nocolor\'): Output will not be coloured.',
''
);
echo implode($newline,$usage);
}
function comparison_by($property,$a,$b) {
if ((!property_exists($a,$property)) || (!property_exists($b,$property))) throw new Exception("Property does not exist in a passed object");
if ($a->$property == 'unknown') $a->$property = 0;
if ($b->$property == 'unknown') $b->$property = 0;
if ($a->$property == $b->$property) return 0;
return ($a->$property > $b->$property ? -1 : 1);
}
function printinstancestats($instance_array,$title) {
global $newline,$morestats,$topinstances;
global $users,$statuses,$connections;
uasort($instance_array,function($a,$b) {
return comparison_by('users',$a,$b);
});
echo getColoredString($newline.'Top ','white').getColoredString($topinstances.' ','light_green').$title.getColoredString(':','white').$newline;
if ($morestats) echo getColoredString('[By users]','light_cyan').$newline;
foreach (array_slice($instance_array,0,$topinstances) as $instance=>$instance_obj) {
echo getColoredString($instance,($instance_obj->up?'light_purple':'red')).getColoredString(': ','white').
getColoredString($instance_obj->users.' users ','light_cyan').
getColoredString('(','white').getColoredString((int)((int)($instance_obj->users)/$users*100).'%','light_green').getColoredString(') - ','white').
getColoredString($instance_obj->statuses.' statuses ','light_red').
getColoredString('(','white').getColoredString((int)((int)($instance_obj->statuses)/$statuses*100).'%','light_green').getColoredString(') - ','white').
getColoredString($instance_obj->connections.' connections','cyan').$newline;
}
if ($morestats) {
uasort($instance_array,function($a,$b) {
return comparison_by('statuses',$a,$b);
});
echo getColoredString('[By statuses]','light_red').$newline;
foreach (array_slice($instance_array,0,$topinstances) as $instance=>$instance_obj) {
echo getColoredString($instance,($instance_obj->up?'light_purple':'red')).getColoredString(': ','white').
getColoredString($instance_obj->statuses.' statuses ','light_red').
getColoredString('(','white').getColoredString((int)((int)($instance_obj->statuses)/$statuses*100).'%','light_green').getColoredString(') - ','white').
getColoredString($instance_obj->users.' users ','light_cyan').
getColoredString('(','white').getColoredString((int)((int)($instance_obj->users)/$users*100).'%','light_green').getColoredString(') - ','white').
getColoredString($instance_obj->connections.' connections','cyan').$newline;
}
uasort($instance_array,function($a,$b) {
return comparison_by('connections',$a,$b);
});
echo getColoredString('[By connections]','cyan').$newline;
foreach (array_slice($instance_array,0,$topinstances) as $instance=>$instance_obj) {
echo getColoredString($instance,($instance_obj->up?'light_purple':'red')).getColoredString(': ','white').
getColoredString($instance_obj->connections.' connections','cyan').getColoredString(' - ','white').
getColoredString($instance_obj->users.' users ','light_cyan').
getColoredString('(','white').getColoredString((int)((int)($instance_obj->users)/$users*100).'%','light_green').getColoredString(') - ','white').
getColoredString($instance_obj->statuses.' statuses ','light_red').
getColoredString('(','white').getColoredString((int)((int)($instance_obj->statuses)/$statuses*100).'%','light_green').getColoredString(')','white').$newline;
}
}
}
$hit_once = false;
$old_users = 0;
$new_users = 0;
$new_users_since_start = 0;
$old_statuses = 0;
$new_statuses = 0;
$new_statuses_since_start = 0;
$newline = "\r\n";
$unused_array = array();
// It's a shame I have to do this, but... the following array will contain manually-added instances that are known to (now, or in the past) misrepresent their user count.
// Instances in this list will be hardcoded to show "unknown" (ie, 0) users.
$misbehaving_instances = array('mastodon.potproject.net');
// arguments
$topinstances = 10;
$morestats = false;
$colour = true;
if ($argc > 1) {
$filename = array_shift($argv);
foreach ($argv as $arg) {
$arglower = str_replace('-','',strtolower($arg));
if ($arglower == "more") {
$morestats = true;
continue;
}
if (($arglower == "nocolour") || ($arglower == "nocolor")) { // people will use the spelling that suits them, better to support both
$colour = false;
}
if (is_numeric($arg)) {
$topinstances = $arg;
}
if ($arglower == "help") die(usage($filename));
}
}
while(1) {
$array = @json_decode(file_get_contents('https://instances.mastodon.xyz/instances.json'));
if (!$array) {
if (!$hit_once) {
echo getColoredString("Could not contact instances.mastodon.xyz, trying again in 30 seconds...",'red').$newline;
}
sleep(60);
continue;
}
// clear screen
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
proc_close(proc_open('cmd /c cls',array(STDIN,STDOUT,STDERR),$unused_array));
} else {
echo chr(27).chr(91).'H'.chr(27).chr(91).'J';
}
$count = count($array);
$open_instances = $all_instances = array();
$users = 0;
$open_instance_count = 0;
$open_up_instance_count = 0;
$up_instance_count = 0;
$statuses = 0;
$connections = 0;
// iterate through all instances to get usercount, open instance list etc.
foreach($array as $instance) {
if ((in_array($instance->name,$misbehaving_instances)) || (!property_exists($instance,'users'))) $instance->users = 'unknown';
if (!property_exists($instance,'statuses')) $instance->statuses = 'unknown';
if (!property_exists($instance,'connections')) $instance->connections = 'unknown';
$users += $instance->users;
$statuses += $instance->statuses;
$connections += $instance->connections;
if (@$instance->openRegistrations == true) {
$open_instance_count++;
$open_instances[(!$instance->up ? '[DOWN] ' : '').$instance->name] = (object)array('users'=>$instance->users,'statuses'=>$instance->statuses,'connections'=>$instance->connections,'up'=>$instance->up);
if (@$instance->up == true) $open_up_instance_count++;
}
$all_instances[(!$instance->up ? '[DOWN] ' : '').$instance->name] = (object)array('users'=>$instance->users,'statuses'=>$instance->statuses,'connections'=>$instance->connections,'up'=>$instance->up);
if (@$instance->up == true) $up_instance_count++;
}
echo getColoredString('For news and updates follow : ','white') .
getColoredString('@','light_green') . getColoredString('slipstream','yellow') . getColoredString('@','light_green') . getColoredString('mastodon.social','yellow') . $newline;
echo getColoredString('Instance count..............: ','white') . getColoredString($count,'yellow') .
getColoredString(' (','white') . getColoredString($up_instance_count,'light_green') . getColoredString(' up)','white') . $newline;
echo getColoredString('Open instances..............: ','white') . getColoredString($open_instance_count,'yellow') .
getColoredString(' (','white') . getColoredString($open_up_instance_count,'light_green') . getColoredString(' up)','white') . $newline;
echo getColoredString('Total users.................: ','white') . getColoredString($users,'yellow');
if (($old_users != 0) && ($old_users != $users)) {
$new_users = $users - $old_users;
if ($new_users < 0) $new_users = 0;
$new_users_since_start += $new_users;
echo getColoredString(' (','white').getColoredString('+' . $new_users,'light_green') . getColoredString(')','white');
} else if ($new_users > 0) {
echo getColoredString(' (','white').getColoredString('+' . $new_users,'light_green') . getColoredString(')','white');
}
echo $newline;
echo getColoredString('New users...................: ','white') .
getColoredString($new_users_since_start,'green') . getColoredString(' since start of script','white') . $newline;
echo getColoredString('Average users/instance......: ','white') . getColoredString('~' . (int)($users/$count),'yellow') . $newline;
echo getColoredString('Total statuses..............: ','white') . getColoredString($statuses,'yellow');
if (($old_statuses != 0) && ($old_statuses != $statuses)) {
$new_statuses = $statuses - $old_statuses;
if ($new_statuses < 0) $new_statuses = 0;
$new_statuses_since_start += $new_statuses;
echo getColoredString(' (','white') . getColoredString('+' . $new_statuses,'light_green') . getColoredString(')','white');
} else if ($new_statuses > 0) {
echo getColoredString(' (','white') . getColoredString('+' . $new_statuses,'light_green') . getColoredString(')','white');
}
echo $newline;
echo getColoredString('New statuses................: ','white') . getColoredString($new_statuses_since_start,'green') . getColoredString(' since start of script','white') . $newline;
echo getColoredString('Average statuses/instance...: ','white') . getColoredString('~' . (int)($statuses/$count),'yellow') . $newline;
echo getColoredString('Average connections/instance: ','white') . getColoredString('~' . (int)($connections/$count),'yellow') . $newline;
$old_users = $users;
$old_statuses = $statuses;
printinstancestats($open_instances,getColoredString('open instances','white'));
printinstancestats($all_instances,getColoredString('instances overall','white'));
$hit_once = true;
// wait 60 seconds for the next round
sleep(60);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.