app.py 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. #!/usr/bin/env python3
  2. from telnetlib import Telnet
  3. import toml
  4. from flask import Flask, jsonify, render_template_string
  5. app = Flask(__name__)
  6. def get_users():
  7. with open("secret.toml") as infile:
  8. cfg = toml.load(infile)
  9. login = ("login %s %s\n" % (cfg["user"], cfg["pass"])).encode("utf-8")
  10. with Telnet(cfg["host"], cfg["port"], 5) as tn:
  11. print("connection")
  12. print(tn.read_until(b"\n").decode("ascii"))
  13. print(tn.read_until(b"\n").decode("ascii"))
  14. print("----")
  15. tn.write(login)
  16. print("after login")
  17. print(tn.read_until(b"\n").decode("ascii"))
  18. print("----")
  19. tn.write(b"use 1 -virtual\n")
  20. print("after use")
  21. print(tn.read_until(b"\n").decode("ascii"))
  22. print("----")
  23. tn.write(b"clientlist\n")
  24. response = tn.read_until(b"\n").decode("ascii")
  25. print("after clientlist")
  26. print(response)
  27. print(tn.read_until(b"\n").decode("ascii"))
  28. print("----")
  29. # entries separated by |'s
  30. entries = response.split("|")
  31. # entries contain key=value pairs separated by spaces
  32. pairs = [[pr.split("=", 1) for pr in ent.split()] for ent in entries]
  33. # rearrange these into maps for convenience
  34. entry_maps = [{k: v for k, v in pr} for pr in pairs]
  35. # combine the maps into one large map, ignoring serveradmin query user
  36. client_info = {info["client_nickname"]: info for info in entry_maps if "serveradmin" not in info["client_nickname"]}
  37. for k, v in client_info.items():
  38. tn.write(f"clientinfo clid={v['clid']}\n".encode("utf-8"))
  39. response = tn.read_until(b"\n").decode("ascii")
  40. print(f"after clientinfo for {k}")
  41. print(response)
  42. print(tn.read_until(b"\n").decode("ascii"))
  43. print("----")
  44. # info is key=value pairs separated by spaces
  45. pairs = [ent.split("=", 1) for ent in response.split() if "=" in ent]
  46. # rearrange into a map and put in the client_info
  47. v["client_info"] = {k: v for k, v in pairs}
  48. tn.write(b"quit\n")
  49. print("after quit")
  50. print(tn.read_until(b"\n").decode("ascii"))
  51. users = []
  52. for name, info in client_info.items():
  53. user_text = name
  54. audio_status = []
  55. if info["client_info"].get("client_input_muted", "0") == "1":
  56. audio_status.append("Mic muted")
  57. if info["client_info"].get("client_output_muted", "0") == "1":
  58. audio_status.append("Sound muted")
  59. if len(audio_status) > 0:
  60. user_text += f" ({', '.join(audio_status)})"
  61. users.append(user_text)
  62. return users
  63. @app.route("/")
  64. def get_status():
  65. return jsonify({"users": get_users()})
  66. @app.route("/page")
  67. def get_status_page():
  68. users = get_users()
  69. if len(users) == 0:
  70. text = "No one in teamspeak!"
  71. elif len(users) == 1:
  72. text = f"Only {users[0]}"
  73. else:
  74. text = "I see the following people: " + ", ".join(users)
  75. return render_template_string("""
  76. <!doctype html>
  77. <title>Teamspeak Server Status</title>
  78. <style>
  79. body {
  80. margin: 0px 0px 0px 0px;
  81. padding: 0px 0px 0px 0px;
  82. font-family: verdana, arial, helvetica, sans-serif;
  83. color: #ccc;
  84. background-color: #333;
  85. }
  86. h1 {
  87. font-size: 24px;
  88. line-height: 44px;
  89. font-weight: bold;
  90. margin-top: 0;
  91. margin-bottom: 0;
  92. }
  93. </style>
  94. {% if scrolling %}
  95. <marquee direction="up" style="height 600px" behavior="alternate">
  96. <marquee direction="right" style="width 600px" behavior="alternate">
  97. {% endif %}
  98. <div class="page">
  99. <h1>TeamSpeak Server Status</h1>
  100. {{ r }}
  101. </div>
  102. {% if scrolling %}
  103. </marquee>
  104. </marquee>
  105. {% endif %}
  106. """, scrolling=True, r=text)
  107. if __name__ == "__main__":
  108. app.run("0.0.0.0", 5000, debug=True, threaded=True)