From e9f612fe43148f7fcecb37a4dfcc6b51945081a6 Mon Sep 17 00:00:00 2001
From: atoav <dh@atoav.com>
Date: Thu, 23 Apr 2020 15:30:34 +0200
Subject: [PATCH] Refactor, add more leaderboards (incl. Duration)

---
 bbbmon/__pycache__/bbbmon.cpython-37.pyc | Bin 9383 -> 10488 bytes
 bbbmon/bbbmon.py                         | 119 ++++++++++++++++-------
 2 files changed, 84 insertions(+), 35 deletions(-)

diff --git a/bbbmon/__pycache__/bbbmon.cpython-37.pyc b/bbbmon/__pycache__/bbbmon.cpython-37.pyc
index 69ead85e11db37e9ebcc685f10df53ba78d5c9c0..1d540c3a3ed4c1abcb44c95fc56ad8b6f28e9cec 100644
GIT binary patch
delta 5395
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
Y0GANA0Gj}}2$v9#fTolR2MZS?04x}s;s5{u

delta 4081
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

diff --git a/bbbmon/bbbmon.py b/bbbmon/bbbmon.py
index 49ef461..ec3e2d0 100644
--- a/bbbmon/bbbmon.py
+++ b/bbbmon/bbbmon.py
@@ -3,6 +3,7 @@
 
 import os
 import hashlib
+from datetime import datetime, timedelta
 import requests
 import appdirs
 from xml.etree import cElementTree as ElementTree
@@ -10,13 +11,21 @@ from typing import NewType, Optional, Tuple, Iterable
 
 
 
-
+# Default path
 SERVER_PROPERTIES_FILE = "/usr/share/bbb-web/WEB-INF/classes/bigbluebutton.properties"
 
-
+# Type definitions
 Secret = NewType('Secret', str)
 Url    = NewType('Url', str)
 
+FRIENDLY_KEYNAMES = {
+    "participantCount": "Participants",
+    "listenerCount": "only listening",
+    "voiceParticipantCount": "Mics on",
+    "videoCount": "Webcams on",
+    "moderatorCount": "Number of Moderators"
+}
+
 
 
 class XmlListConfig(list):
@@ -116,7 +125,11 @@ def request_meetings(secret: Secret, bbb_url: Url) -> XmlDictConfig:
         exit()
     return xmldict
 
+
 def get_meetings(secret: Secret, bbb_url: Url) -> Iterable[XmlDictConfig]:
+    """
+    Request meetings and return a list of them. Sorted by biggest first
+    """
     meetings = []
     d = request_meetings(secret, bbb_url)
 
@@ -143,6 +156,32 @@ def get_presenter(meeting: XmlDictConfig) -> Optional[XmlDictConfig]:
         return None
 
 
+def get_duration(meeting: XmlDictConfig) -> timedelta:
+    """
+    Return the duration of a meeting
+    """
+    timestamp = int(meeting["startTime"][:-3])
+    start_time = datetime.fromtimestamp(timestamp)
+    duration = datetime.now() - start_time
+    return duration
+
+
+def strfdelta(duration: timedelta, fmt: str) -> str:
+    """
+    Helper function for datetime.timedelta formatting, use like this:
+    strfdelta(delta_obj, "{days} days {hours}:{minutes}:{seconds}")
+    """
+    d = {"days": duration.days}
+    d["hours"], remainder = divmod(duration.seconds, 3600)
+    d["minutes"], d["seconds"] = divmod(remainder, 60)
+    return fmt.format(**d)
+
+
+def format_duration(meeting: XmlDictConfig) -> str:
+    duration = get_duration(meeting)
+    return strfdelta(duration, "{hours}:{minutes}")
+
+
 
 def get_formated_presenter_name(meeting: XmlDictConfig) -> str:
     """
@@ -150,42 +189,51 @@ def get_formated_presenter_name(meeting: XmlDictConfig) -> str:
     """
     presenter = get_presenter(meeting)
     if presenter is not None:
-        return "{} ({})".format(presenter["fullName"], presenter["userID"])
+        return "{:<30} ({})".format(presenter["fullName"], presenter["userID"])
     else:
         return "no Presenter"
 
 
+def print_leaderboard(meetings: Iterable[XmlDictConfig], key: str):
+    """
+    Print a leaderboard of all meetings sorted by a given key (e.g. 
+    participantCount)
+    """
+    print("LEADERBOARD ({})".format(FRIENDLY_KEYNAMES[key]))
+    for m in meetings:
+        print("{:>5} {:<45} {}".format(m[key], m["meetingName"], get_formated_presenter_name(m))) 
+
+
+def print_duration_leaderboard(meetings: Iterable[XmlDictConfig]):
+    """
+    Print a leaderboard of all meetings sorted by a given key (e.g. 
+    participantCount)
+    """
+    print("LEADERBOARD (Duration)")
+    by_duration = sorted([m for m in meetings], key=lambda x:int(get_duration(x).total_seconds()), reverse=True)
+
+    for m in by_duration:
+        print("{:>5} {:<45} {}".format(format_duration(m), m["meetingName"], get_formated_presenter_name(m))) 
+
+
 def print_overview(secret: Secret, bbb_url: Url):
-    d = request_meetings(secret, bbb_url)
+    """
+    Get the meetings and print out an overview of the current bbb-usage
+    """
+    meetings = get_meetings(secret, bbb_url)
 
-    # If there is more than one meeting the type is XmlListConfig otherwise XmlDictConfig
-    if type(d["meetings"]["meeting"]) is XmlListConfig:
-        n_running = len([m for m in d["meetings"]["meeting"] if m["running"] == "true"])
-        n_recording = len([m for m in d["meetings"]["meeting"] if m["recording"] == "true"])
-        n_participants = sum([int(m["participantCount"]) for m in d["meetings"]["meeting"] if m["running"] == "true"])
-        n_listeners = sum([int(m["listenerCount"]) for m in d["meetings"]["meeting"] if m["running"] == "true"])
-        n_voice = sum([int(m["voiceParticipantCount"]) for m in d["meetings"]["meeting"] if m["running"] == "true"])
-        n_video = sum([int(m["videoCount"]) for m in d["meetings"]["meeting"] if m["running"] == "true"])
-        n_moderator = sum([int(m["moderatorCount"]) for m in d["meetings"]["meeting"] if m["running"] == "true"])
-        biggest_room = max([m for m in d["meetings"]["meeting"] if m["running"] == "true"], key=lambda x:int(x['participantCount']))
-        rooms_by_size = sorted([m for m in d["meetings"]["meeting"] if m["running"] == "true"], key=lambda x:int(x['participantCount']), reverse=True)
-    elif type(d["meetings"]["meeting"]) is XmlDictConfig:
-        m = d["meetings"]["meeting"][0]
-        n_running = 1
-        if m["recording"] == "true": 
-            n_recording = 1 
-        else:
-            n_recording = 0
-        n_participants = int(m["participantCount"])
-        n_listeners = int(m["listenerCount"])
-        n_voice = int(m["voiceParticipantCount"])
-        n_video = int(m["videoCount"])
-        n_moderator = int(m["moderatorCount"])
-        biggest_room = m
-    else:
-        print("It appears there are no rooms running.")
+    if len(meetings) == 0:
+        print("There are no meetings running now.")
         exit()
 
+    n_running = len(meetings)
+    n_recording = len([m for m in meetings if m["recording"] == "true"])
+    n_participants = sum([int(m["participantCount"]) for m in meetings])
+    n_listeners = sum([int(m["listenerCount"]) for m in meetings])
+    n_voice = sum([int(m["voiceParticipantCount"]) for m in meetings])
+    n_video = sum([int(m["videoCount"]) for m in meetings])
+    n_moderator = sum([int(m["moderatorCount"]) for m in meetings])
+
     print("MEETINGS on {}:".format(bbb_url))
     print("   ├─── {:>4} running".format(n_running))
     print("   └─── {:>4} recording".format(n_recording))
@@ -198,12 +246,13 @@ def print_overview(secret: Secret, bbb_url: Url):
     print("     └─ {:>4} moderators".format(n_moderator))
 
     print()
-    print("Most participants ({}): {}, Presenter: {}".format(biggest_room["participantCount"], biggest_room["meetingName"], get_formated_presenter_name(biggest_room)))
-
+    print_leaderboard(meetings, "participantCount")
+    print()
+    print_leaderboard(meetings, "videoCount")
+    print()
+    print_leaderboard(meetings, "voiceParticipantCount")
     print()
-    print("LEADERBOARD (Participants)")
-    for m in rooms_by_size:
-        print("{:>5} {:<45} {}".format(m["participantCount"], m["meetingName"], get_formated_presenter_name(m)))
+    print_duration_leaderboard(meetings)
 
 
 
-- 
GitLab