From e6294777a0c9ac01f99307ecc79ef5f97f718e4d Mon Sep 17 00:00:00 2001
From: atoav <dh@atoav.com>
Date: Thu, 30 Apr 2020 13:30:13 +0200
Subject: [PATCH] Add --compact mode and -n

---
 bbbmon/bbbmon.py   | 15 +++++++--
 bbbmon/meetings.py | 34 ++++++++++++++------
 bbbmon/printing.py | 80 ++++++++++++++++++++++++++++++++++++----------
 pyproject.toml     |  2 +-
 4 files changed, 101 insertions(+), 30 deletions(-)

diff --git a/bbbmon/bbbmon.py b/bbbmon/bbbmon.py
index 01b8125..4124292 100755
--- a/bbbmon/bbbmon.py
+++ b/bbbmon/bbbmon.py
@@ -57,16 +57,18 @@ def main(userconfig):
 @click.option('--userconfig', '-u', is_flag=True, help="Use user config even if on server")
 @click.option('--endpoint', '-e', multiple=True, help="Filter by one or more endpoints as named in the user configuration (e.g. [servername]). Order is respected.")
 @click.option('--watch', '-w', help="Run repeatedly with the given interval in seconds", type=click.IntRange(2, 2147483647, clamp=True))
+@click.option('-n', help="The number of meetings to show in the leaderboards (Default: 5)", type=int)
 @click.option('--leaderboards/--no-leaderboards', default=True, show_default=True, help="Hide or show the meeting leaderboards")
 @click.option('--participants/--no-participants', default=True, show_default=True, help="Hide or show the participants")
 @click.option('--meetings/--no-meetings', default=True, show_default=True, help="Hide or show the meetings")
 @click.option('--presenter/--no-presenter', default=True, show_default=True, help="Hide or show the presenters")
 @click.option('--presenter-id/--no-presenter-id', default=False, show_default=True, help="Hide or show the presenter IDs")
 @click.option('--short', '-s', is_flag=True, help="Print less")
+@click.option('--compact', '-c', is_flag=True, help="Print compactly")
 @click.option('--twolines', '-2', is_flag=True, help="Print essentials on two lines")
 @click.option('--all', '-a', 'all_', is_flag=True, help="Print all")
 @click.option('--fancy/--no-fancy', default=True, show_default=True, help="Use fancy headers")
-def meetings(ctx, userconfig, short, all_, twolines, leaderboards, participants, presenter, watch, presenter_id, meetings, endpoint, fancy):
+def meetings(ctx, userconfig, short, compact, n, all_, twolines, leaderboards, participants, presenter, watch, presenter_id, meetings, endpoint, fancy):
     """View currently active meetings"""
     if short:
         leaderboards = False
@@ -76,6 +78,13 @@ def meetings(ctx, userconfig, short, all_, twolines, leaderboards, participants,
         presenter = True
         presenter_id = True
         meetings = True
+        if n is None:
+            n = 99999
+    if compact:
+        if n is None:
+            n = 1
+    if n is None:
+        n = 5
 
     config = init_config(userconfig)
     config.filter_endpoints(endpoint)
@@ -84,13 +93,13 @@ def meetings(ctx, userconfig, short, all_, twolines, leaderboards, participants,
             if twolines:
                 meetings_twolines(config, watch, fancy)
             else:
-                list_meetings(config, leaderboards, participants, presenter, presenter_id, meetings, watch, fancy)
+                list_meetings(config, leaderboards, n, participants, presenter, presenter_id, meetings, watch, fancy, compact)
             time.sleep(watch)
     else:
         if twolines:
             meetings_twolines(config, watch, fancy)
         else:
-            list_meetings(config, leaderboards, participants, presenter, presenter_id, meetings, watch, fancy)
+            list_meetings(config, leaderboards, n, participants, presenter, presenter_id, meetings, watch, fancy, compact)
 
 
 
diff --git a/bbbmon/meetings.py b/bbbmon/meetings.py
index 15feba8..53e5c16 100644
--- a/bbbmon/meetings.py
+++ b/bbbmon/meetings.py
@@ -104,7 +104,7 @@ def get_duration(meeting: XmlDictConfig) -> timedelta:
     return duration
 
 
-def list_meetings(config: Config, leaderboards: bool, participants: bool, presenter: bool, presenter_id: bool, show_meetings: bool, watch: int, fancy: bool):
+def list_meetings(config: Config, leaderboards: bool, n: int, participants: bool, presenter: bool, presenter_id: bool, show_meetings: bool, watch: int, fancy: bool, compact: bool):
     """
     For each endpoint in the configuration get the active meetings and print 
     out an overview of the current bbb-usage
@@ -143,13 +143,13 @@ def list_meetings(config: Config, leaderboards: bool, participants: bool, presen
         n_video = sum([int(m["videoCount"]) for m in meeting])
         n_moderator = sum([int(m["moderatorCount"]) for m in meeting])
 
-        if show_meetings:
+        if show_meetings and not compact:
             printing.print_header(endpoint.name, "MEETINGS", fancy)
             print("   ├─── {:>4} running".format(n_running))
             print("   └─── {:>4} recording".format(n_recording))
             print()
 
-        if participants:
+        if participants and not compact:
             printing.print_header(endpoint.name, "PARTICIPANTS across all {} rooms".format(n_running), fancy)
             print("   └─┬─ {:>4} total".format(n_participants))
             print("     ├─ {:>4} listening only".format(n_listeners))
@@ -157,15 +157,29 @@ def list_meetings(config: Config, leaderboards: bool, participants: bool, presen
             print("     ├─ {:>4} video on".format(n_video))
             print("     └─ {:>4} moderators".format(n_moderator))
 
+        if compact: 
+            h1 = printing.format_header(endpoint.name, "MEETINGS", fancy) 
+            h2 = printing.format_header("", "PARTICIPANTS across all {} rooms".format(n_running), fancy)
+            s1 ="   ├─── {:>4} running  ".format(n_running)
+            s2 ="   └─── {:>4} recording".format(n_recording)
+            p1 ="   └─┬─ {:>4} total".format(n_participants)
+            p2 ="     ├─ {:>4} listening only".format(n_listeners)
+            p3 ="     ├─ {:>4} mic on".format(n_voice)
+            p4 ="     ├─ {:>4} video on".format(n_video)
+            p5 ="     └─ {:>4} moderators".format(n_moderator)
+            print("{:<20}  {}".format(h1.rstrip(), h2))
+            print("{:<22} {}".format(s1, p1))
+            print("{:<22} {}".format(s2, p2))
+            print("{:<22} {}".format("", p3))
+            print("{:<22} {}".format("", p4))
+            print("{:<22} {}".format("", p5))
+
         if leaderboards:
             print()
-            printing.print_leaderboard(meeting, "participantCount", endpoint.name, presenter, presenter_id, fancy)
-            print()
-            printing.print_leaderboard(meeting, "videoCount", endpoint.name, presenter, presenter_id, fancy)
-            print()
-            printing.print_leaderboard(meeting, "voiceParticipantCount", endpoint.name, presenter, presenter_id, fancy)
-            print()
-            printing.print_duration_leaderboard(meeting, endpoint.name, presenter, presenter_id, fancy)
+            printing.print_leaderboard(meeting, n, "participantCount", endpoint.name, presenter, presenter_id, fancy)
+            printing.print_leaderboard(meeting, n, "videoCount", endpoint.name, presenter, presenter_id, fancy)
+            printing.print_leaderboard(meeting, n, "voiceParticipantCount", endpoint.name, presenter, presenter_id, fancy)
+            printing.print_duration_leaderboard(meeting, n, endpoint.name, presenter, presenter_id, fancy)
 
 
 
diff --git a/bbbmon/printing.py b/bbbmon/printing.py
index 208fc11..9457c33 100644
--- a/bbbmon/printing.py
+++ b/bbbmon/printing.py
@@ -61,43 +61,91 @@ def get_formated_presenter_name(meeting: XmlDictConfig) -> str:
         return "no Presenter"
 
 
-def print_leaderboard(meetings: Iterable[XmlDictConfig], key: str, endpoint_name: str, presenter: bool, presenter_id: bool, fancy: bool):
+def print_leaderboard(meetings: Iterable[XmlDictConfig], n: int, key: str, endpoint_name: str, presenter: bool, presenter_id: bool, fancy: bool):
     """
     Print a leaderboard of all meetings sorted by a given key (e.g. 
     participantCount)
     """
-    print_header(endpoint_name, "LEADERBOARD ({})".format(FRIENDLY_KEYNAMES[key]), fancy)
+    if n==1:
+        prefix = "Most"
+    else:
+        prefix = "By"
+    # Stay on same line if n == 1
+    print_header(endpoint_name, "{} {}".format(prefix, FRIENDLY_KEYNAMES[key]), fancy, n != 1)
     sorted_by = sorted([m for m in meetings], key=lambda x:int(x[key]), reverse=True)
-    for m in sorted_by:
+    more = len(sorted_by[:n]) != len(sorted_by)
+    if n != 1:
+        for m in sorted_by[:n]:
+            if presenter:
+                if presenter_id:
+                    print("{:>5} {:<45} {}".format(m[key], m["meetingName"], get_formated_presenter_name_id(m))) 
+                else:
+                    print("{:>5} {:<45} {}".format(m[key], m["meetingName"], get_formated_presenter_name(m))) 
+            else:
+                print("{:>5} {}".format(m[key], m["meetingName"]))
+        if more:
+            print("    {}".format("."*(len(sorted_by)-len(sorted_by[:n]))))
+        print()
+    else:
+        m = sorted_by[0]
         if presenter:
             if presenter_id:
-                print("{:>5} {:<45} {}".format(m[key], m["meetingName"], get_formated_presenter_name_id(m))) 
+                print("{:>8} {:<45} {}".format(m[key], m["meetingName"], get_formated_presenter_name_id(m))) 
             else:
-                print("{:>5} {:<45} {}".format(m[key], m["meetingName"], get_formated_presenter_name(m))) 
+                print("{:>8} {:<45} {}".format(m[key], m["meetingName"], get_formated_presenter_name(m))) 
         else:
-            print("{:>5} {}".format(m[key], m["meetingName"]))
+            print("{:>8} {}".format(m[key], m["meetingName"]))
 
 
-def print_duration_leaderboard(meetings: Iterable[XmlDictConfig], endpoint_name: str, presenter: bool, presenter_id: bool, fancy: bool):
+def print_duration_leaderboard(meetings: Iterable[XmlDictConfig], n: int, endpoint_name: str, presenter: bool, presenter_id: bool, fancy: bool):
     """
     Print a leaderboard of all meetings sorted by a given key (e.g. 
     participantCount)
     """
-    print_header(endpoint_name, "LEADERBOARD (Duration)", fancy)
+    if n==1:
+        prefix = "Most"
+    else:
+        prefix = "By"
+    # Stay on same line if n == 1
+    print_header(endpoint_name, "{} Duration".format(prefix, ), fancy, n != 1)
     by_duration = sorted([m for m in meetings], key=lambda x:int(bbbmon.meetings.get_duration(x).total_seconds()), reverse=True)
-
-    for m in by_duration:
+    more = len(by_duration[:n]) != len(by_duration)
+    if n != 1:
+        for m in by_duration[:n]:
+            if presenter:
+                if presenter_id:
+                    print("{:>12} {:<38} {}".format(format_duration(m), m["meetingName"], get_formated_presenter_name_id(m))) 
+                else:
+                    print("{:>12} {:<38} {}".format(format_duration(m), m["meetingName"], get_formated_presenter_name(m))) 
+            else:
+                print("{:>12} {}".format(format_duration(m), m["meetingName"]))
+        if more:
+            print("    {}".format("."*(len(by_duration)-len(by_duration[:n]))))
+        print()
+    else:
+        m = by_duration[0]
         if presenter:
             if presenter_id:
-                print("{:>12} {:<38} {}".format(format_duration(m), m["meetingName"], get_formated_presenter_name_id(m))) 
+                print("{:>4} {:<45} {}".format(format_duration(m), m["meetingName"], get_formated_presenter_name_id(m))) 
             else:
-                print("{:>12} {:<38} {}".format(format_duration(m), m["meetingName"], get_formated_presenter_name(m))) 
+                print("{:>4} {:<45} {}".format(format_duration(m), m["meetingName"], get_formated_presenter_name(m))) 
         else:
-            print("{:>12} {}".format(format_duration(m), m["meetingName"]))
+            print("{:>4} {}".format(format_duration(m), m["meetingName"]))
+
+
+def print_header(endpoint_name: str, text: str, fancy=True, newline=True):
+    click.echo(format_header(endpoint_name, text, fancy), nl=newline)
 
 
-def print_header(endpoint_name: str, text: str, fancy=True):
+def format_header(endpoint_name: str, text: str, fancy=True) -> str:
     if fancy:
-        click.echo(click.style("  [{}] {}  ".format(endpoint_name, text), fg='black', bg='white', bold=True))
+        if len(endpoint_name) > 0:
+            block = click.style("  [{}] {}  ".format(endpoint_name, text), fg='black', bg='white', bold=True)
+        else:
+            block = click.style("  {} {}  ".format(endpoint_name, text), fg='black', bg='white', bold=True)
     else:
-        print("[{}] {}".format(endpoint_name, text))
\ No newline at end of file
+        if len(endpoint_name) > 0:
+            block = "[{}] {}".format(endpoint_name, text)
+        else:
+            block = "{} {}".format(endpoint_name, text)
+    return "{}{}".format(block, " "*(20-len(endpoint_name+text)))
\ No newline at end of file
diff --git a/pyproject.toml b/pyproject.toml
index ce067b6..83d1f9a 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,6 +1,6 @@
 [tool.poetry]
 name = "bbbmon"
-version = "0.1.18"
+version = "0.1.19"
 description = "A small CLI utility to monitor bbb usage"
 authors = ["David Huss <david.huss@hfbk-hamburg.de>"]
 maintainers = ["David Huss <david.huss@hfbk-hamburg.de>"]
-- 
GitLab