bbbctl 0.4.2__tar.gz → 0.5.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,9 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bbbctl
3
- Version: 0.4.2
3
+ Version: 0.5.0
4
4
  Summary: BigBlueButton API command-line client
5
5
  Author-email: Marcel Hellkamp <marc@gsites.de>
6
- Requires-Python: >=3.6
6
+ Requires-Python: >=3.10
7
7
  Description-Content-Type: text/markdown
8
8
  License-Expression: MIT
9
9
  Classifier: Programming Language :: Python :: 3
@@ -92,7 +92,7 @@ for meeting in client.getMeetings():
92
92
 
93
93
  # License
94
94
 
95
- Copyright (c) 2020-2062, Marcel Hellkamp.
95
+ Copyright (c) 2020-2026, Marcel Hellkamp.
96
96
 
97
97
  Permission is hereby granted, free of charge, to any person obtaining a copy
98
98
  of this software and associated documentation files (the "Software"), to deal
@@ -78,7 +78,7 @@ for meeting in client.getMeetings():
78
78
 
79
79
  # License
80
80
 
81
- Copyright (c) 2020-2062, Marcel Hellkamp.
81
+ Copyright (c) 2020-2026, Marcel Hellkamp.
82
82
 
83
83
  Permission is hereby granted, free of charge, to any person obtaining a copy
84
84
  of this software and associated documentation files (the "Software"), to deal
@@ -6,10 +6,10 @@ build-backend = "flit_core.buildapi"
6
6
 
7
7
  [project]
8
8
  name = "bbbctl"
9
- version = "0.4.2"
9
+ version = "0.5.0"
10
10
  description = "BigBlueButton API command-line client"
11
11
  readme = "README.md"
12
- requires-python = ">=3.6"
12
+ requires-python = ">=3.10"
13
13
  license = "MIT"
14
14
  authors = [
15
15
  { name = "Marcel Hellkamp", email = "marc@gsites.de" },
@@ -319,8 +319,8 @@ CREATE_LOCKS = {
319
319
  "cam": "lockSettingsDisableCam",
320
320
  "mic": "lockSettingsDisableMic",
321
321
  "chat": "lockSettingsDisablePublicChat",
322
- "pm": "lockSettingDisablePrivateChat",
323
- "notes": "lockSettingDisableNotes",
322
+ "pm": "lockSettingsDisablePrivateChat",
323
+ "notes": "lockSettingsDisableNotes",
324
324
  "userlist": "lockSettingsHideUserList",
325
325
  "cursor": "lockSettingsHideViewersCursor",
326
326
  }
@@ -346,7 +346,7 @@ class BBBApiClient:
346
346
  self.api = api.rstrip("/")
347
347
  self.secret = secret
348
348
  self.ssl = ssl_context or ssl.create_default_context()
349
- self.debug = max(0, debug)
349
+ self.debug = max(0, debug or 0)
350
350
 
351
351
  def makeurl(self, command, **query):
352
352
  query = urllib.parse.urlencode(
@@ -367,7 +367,7 @@ class BBBApiClient:
367
367
  with urllib.request.urlopen(url, context=self.ssl) as f:
368
368
  xml = f.read().decode("utf8")
369
369
  if self.debug >= 2:
370
- for line in xml:
370
+ for line in xml.splitlines():
371
371
  print(f"<<< {line}", file=sys.stderr)
372
372
  root = ET.fromstring(xml)
373
373
  if (status := root.find("./returncode")) is None or status.text != "SUCCESS":
@@ -412,8 +412,20 @@ class BBBApiClient:
412
412
 
413
413
  def build_parser():
414
414
 
415
- def csv_type(value):
416
- return value.split(",")
415
+ def csv_choice(choices):
416
+ choices = set(choices)
417
+
418
+ def parse(value):
419
+ items = [item.strip() for item in value.split(",") if item.strip()]
420
+ unknown = [item for item in items if item not in choices]
421
+ if unknown:
422
+ raise argparse.ArgumentTypeError(
423
+ "invalid choice: %s (choose from %s)"
424
+ % (", ".join(unknown), ", ".join(sorted(choices)))
425
+ )
426
+ return items
427
+
428
+ return parse
417
429
 
418
430
  def kv_type(value):
419
431
  k, _, v = value.partition("=")
@@ -422,7 +434,7 @@ def build_parser():
422
434
  return (k, v)
423
435
 
424
436
  parser = argparse.ArgumentParser()
425
- main_sub = parser.add_subparsers(title="Commands")
437
+ main_sub = parser.add_subparsers(title="Commands", required=True)
426
438
 
427
439
  parser.add_argument(
428
440
  "--server",
@@ -456,7 +468,7 @@ def build_parser():
456
468
  "record",
457
469
  help="List, show, publish, unpublish or delete recordings",
458
470
  )
459
- rec_sub = rec.add_subparsers(title="Manage recordings")
471
+ rec_sub = rec.add_subparsers(title="Manage recordings", required=True)
460
472
 
461
473
  cmd = rec_sub.add_parser("list", help="List all recordings")
462
474
  cmd.add_argument("--meeting", help="Filter by external meetingID")
@@ -481,7 +493,7 @@ def build_parser():
481
493
  meet = main_sub.add_parser(
482
494
  "meeting", help="List, inspect, create, join or end meetings"
483
495
  )
484
- meet_sub = meet.add_subparsers()
496
+ meet_sub = meet.add_subparsers(required=True)
485
497
 
486
498
  cmd = meet_sub.add_parser("list", help="List meetings")
487
499
  cmd.add_argument("--sort", help="Sort by a specific key")
@@ -513,8 +525,7 @@ def build_parser():
513
525
  cmd.add_argument(
514
526
  "--lock",
515
527
  help="Shortcuts for --lockSettingsDisable... parameters.",
516
- choices=list(CREATE_LOCKS.keys()),
517
- type=csv_type,
528
+ type=csv_choice(CREATE_LOCKS.keys()),
518
529
  )
519
530
 
520
531
  cmd.add_argument(
@@ -528,15 +539,13 @@ def build_parser():
528
539
  cmd.add_argument(
529
540
  "--disabledFeatures",
530
541
  help="Disable features for this meeting. Set multiple values as comma-separated list.",
531
- choices=CREATE_FEATURES,
532
- type=csv_type,
542
+ type=csv_choice(CREATE_FEATURES),
533
543
  )
534
544
 
535
545
  cmd.add_argument(
536
546
  "--disabledFeaturesExclude",
537
547
  help="Remove featres from the --disabledFeatures list. Set multiple values as comma-separated list.",
538
- choices=CREATE_FEATURES,
539
- type=csv_type,
548
+ type=csv_choice(CREATE_FEATURES),
540
549
  )
541
550
 
542
551
  for name, (type_, help) in CREATE_PARAMS.items():
@@ -635,8 +644,6 @@ def find_bbb_property(name):
635
644
  def main():
636
645
  parser = build_parser()
637
646
  args = parser.parse_args()
638
- if not hasattr(args, "cmd"):
639
- parser.parse_args(sys.argv[1:] + ["-h"])
640
647
 
641
648
  server = (
642
649
  args.server
@@ -799,8 +806,8 @@ def cmd_meet_create(api, args):
799
806
  params = {"meetingID": args.id, "name": args.name}
800
807
 
801
808
  # Process --lock first so it can be overridden by explicit --no-lockSettingsBlaBla
802
- for k, v in CREATE_LOCKS:
803
- if k in args.lock:
809
+ for k, v in CREATE_LOCKS.items():
810
+ if k in (args.lock or []):
804
811
  params[v] = "true"
805
812
 
806
813
  # Apply all CREATE_PARAMS
@@ -814,25 +821,29 @@ def cmd_meet_create(api, args):
814
821
  params[name] = str(value)
815
822
 
816
823
  # Apply --meta key=value
817
- for k, v in args.meta:
824
+ for k, v in args.meta or []:
818
825
  if v:
819
826
  params[f"meta_{k}"] = str(v)
820
827
 
821
828
  # Apply --disable feature,feature
822
829
  disabled = set()
823
830
  enabled = set()
824
- for feature in args.disable or []:
831
+ for feature in args.disabledFeatures or []:
825
832
  if feature in CREATE_FEATURES:
826
833
  disabled.add(feature)
827
- for feature in args.enabled or []:
834
+ for feature in args.disabledFeaturesExclude or []:
828
835
  if feature in CREATE_FEATURES:
829
836
  enabled.add(feature)
830
- disabled.remove(feature)
837
+ disabled.discard(feature)
831
838
  if disabled:
832
839
  params["disabledFeatures"] = ",".join(sorted(disabled))
833
- if disabled:
840
+ if enabled:
834
841
  params["disabledFeaturesExclude"] = ",".join(sorted(enabled))
835
842
 
843
+ # Apply raw key=value parameters last so they can override shortcuts.
844
+ for k, v in args.params:
845
+ params[k] = str(v)
846
+
836
847
  created = api.createMeeting(**params)
837
848
 
838
849
  if args.join:
@@ -897,7 +908,10 @@ def cmd_meet_nuke(api, args):
897
908
  pass
898
909
  else:
899
910
  continue
900
- api.end(meetingID=meeting.find("meetingID").text)
911
+ api.end(
912
+ meetingID=meeting.find("meetingID").text,
913
+ password=meeting.find("moderatorPW").text,
914
+ )
901
915
 
902
916
 
903
917
  def cmd_sign(api, args):
File without changes