├── .dockerignore
├── .gitignore
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE.md
├── README.md
├── SECURITY.md
├── app
├── __pycache__
│ ├── config.cpython-312.pyc
│ ├── func.cpython-312.pyc
│ ├── get_info.cpython-312.pyc
│ ├── routes.cpython-312.pyc
│ └── server.cpython-312.pyc
├── config.py
├── func.py
├── get_info.py
├── routes.py
├── server.py
├── static
│ ├── bg.png
│ ├── css
│ │ ├── 404.css
│ │ └── style.css
│ ├── icons
│ │ ├── arrow.svg
│ │ ├── battery-bolt.svg
│ │ ├── battery-exclamation.svg
│ │ ├── battery_full.svg
│ │ ├── cpu.svg
│ │ ├── down.svg
│ │ ├── off.svg
│ │ ├── ram.svg
│ │ ├── reboot.svg
│ │ ├── service.svg
│ │ ├── sleep.svg
│ │ ├── storage.svg
│ │ ├── temp.svg
│ │ └── up.svg
│ ├── js
│ │ ├── check_updates.js
│ │ ├── indicators.js
│ │ ├── os_badge.js
│ │ └── tabs.js
│ └── logo
│ │ ├── arch.svg
│ │ ├── centos.svg
│ │ ├── debian.svg
│ │ ├── fedora.svg
│ │ ├── hat.svg
│ │ ├── linux.svg
│ │ ├── mac.svg
│ │ ├── manjaro.svg
│ │ ├── mint.svg
│ │ ├── os.svg
│ │ ├── suse.svg
│ │ ├── ubuntu.svg
│ │ └── windows.svg
└── templates
│ ├── error.html
│ └── index.html
├── docker-compose.yaml
├── imgs
├── img_1.png
├── img_2.png
├── img_3.png
├── img_4.png
├── img_5.png
└── img_6.png
├── poetry.lock
├── pyproject.toml
└── requirements.txt
/.dockerignore:
--------------------------------------------------------------------------------
1 | app/__pycache__/get_info.cpython-312.pyc
2 | app/Server
3 | app/__pycache__/
4 | app/API/__pycache__
5 | app/__pycache__
6 | app/__pycache__/server.cpython-312.pyc
7 | app/__pycache__/server.cpython-312.pyc
8 | app/__pycache__/routes.cpython-312.pyc
9 | /app/SDash
10 | .git/
11 | .github/
12 | imgs/
13 | README.md
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | app/__pycache__/get_info.cpython-312.pyc
3 | app/Server
4 | app/__pycache__/
5 | app/API/__pycache__
6 | app/__pycache__
7 | app/__pycache__/server.cpython-312.pyc
8 | app/__pycache__/server.cpython-312.pyc
9 | app/__pycache__/routes.cpython-312.pyc
10 | /app/SDash
11 | app/__pycache__/config.cpython-312.pyc
12 | app/__pycache__/get_info.cpython-312.pyc
13 | /app/__pycache__
14 | app/__pycache__/routes.cpython-312.pyc
15 | /sdash
16 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | We as members, contributors, and leaders pledge to make participation in our
6 | community a harassment-free experience for everyone, regardless of age, body
7 | size, visible or invisible disability, ethnicity, sex characteristics, gender
8 | identity and expression, level of experience, education, socio-economic status,
9 | nationality, personal appearance, race, religion, or sexual identity
10 | and orientation.
11 |
12 | We pledge to act and interact in ways that contribute to an open, welcoming,
13 | diverse, inclusive, and healthy community.
14 |
15 | ## Our Standards
16 |
17 | Examples of behavior that contributes to a positive environment for our
18 | community include:
19 |
20 | - Demonstrating empathy and kindness toward other people
21 | - Being respectful of differing opinions, viewpoints, and experiences
22 | - Giving and gracefully accepting constructive feedback
23 | - Accepting responsibility and apologizing to those affected by our mistakes,
24 | and learning from the experience
25 | - Focusing on what is best not just for us as individuals, but for the
26 | overall community
27 |
28 | Examples of unacceptable behavior include:
29 |
30 | - The use of sexualized language or imagery, and sexual attention or
31 | advances of any kind
32 | - Trolling, insulting or derogatory comments, and personal or political attacks
33 | - Public or private harassment
34 | - Publishing others' private information, such as a physical or email
35 | address, without their explicit permission
36 | - Other conduct which could reasonably be considered inappropriate in a
37 | professional setting
38 |
39 | ## Enforcement Responsibilities
40 |
41 | Community leaders are responsible for clarifying and enforcing our standards of
42 | acceptable behavior and will take appropriate and fair corrective action in
43 | response to any behavior that they deem inappropriate, threatening, offensive,
44 | or harmful.
45 |
46 | Community leaders have the right and responsibility to remove, edit, or reject
47 | comments, commits, code, wiki edits, issues, and other contributions that are
48 | not aligned to this Code of Conduct, and will communicate reasons for moderation
49 | decisions when appropriate.
50 |
51 | ## Scope
52 |
53 | This Code of Conduct applies within all community spaces, and also applies when
54 | an individual is officially representing the community in public spaces.
55 | Examples of representing our community include using an official e-mail address,
56 | posting via an official social media account, or acting as an appointed
57 | representative at an online or offline event.
58 |
59 | ## Enforcement
60 |
61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
62 | reported to the community leaders responsible for enforcement at
63 | night3098games@gmail.com.
64 | All complaints will be reviewed and investigated promptly and fairly.
65 |
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM python:3.11-slim
2 |
3 | WORKDIR /app
4 |
5 | EXPOSE 5000
6 |
7 | COPY . .
8 |
9 | RUN pip install --upgrade pip
10 | RUN pip install --no-cache-dir -r requirements.txt
11 |
12 | CMD ["python3", "app/server.py"]
13 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # Apache License
2 |
3 | _Version 2.0, January 2004_
4 | _< >_
5 |
6 | ### Terms and Conditions for use, reproduction, and distribution
7 |
8 | #### 1. Definitions
9 |
10 | “License” shall mean the terms and conditions for use, reproduction, and
11 | distribution as defined by Sections 1 through 9 of this document.
12 |
13 | “Licensor” shall mean the copyright owner or entity authorized by the copyright
14 | owner that is granting the License.
15 |
16 | “Legal Entity” shall mean the union of the acting entity and all other entities
17 | that control, are controlled by, or are under common control with that entity.
18 | For the purposes of this definition, “control” means **(i)** the power, direct or
19 | indirect, to cause the direction or management of such entity, whether by
20 | contract or otherwise, or **(ii)** ownership of fifty percent (50%) or more of the
21 | outstanding shares, or **(iii)** beneficial ownership of such entity.
22 |
23 | “You” (or “Your”) shall mean an individual or Legal Entity exercising
24 | permissions granted by this License.
25 |
26 | “Source” form shall mean the preferred form for making modifications, including
27 | but not limited to software source code, documentation source, and configuration
28 | files.
29 |
30 | “Object” form shall mean any form resulting from mechanical transformation or
31 | translation of a Source form, including but not limited to compiled object code,
32 | generated documentation, and conversions to other media types.
33 |
34 | “Work” shall mean the work of authorship, whether in Source or Object form, made
35 | available under the License, as indicated by a copyright notice that is included
36 | in or attached to the work (an example is provided in the Appendix below).
37 |
38 | “Derivative Works” shall mean any work, whether in Source or Object form, that
39 | is based on (or derived from) the Work and for which the editorial revisions,
40 | annotations, elaborations, or other modifications represent, as a whole, an
41 | original work of authorship. For the purposes of this License, Derivative Works
42 | shall not include works that remain separable from, or merely link (or bind by
43 | name) to the interfaces of, the Work and Derivative Works thereof.
44 |
45 | “Contribution” shall mean any work of authorship, including the original version
46 | of the Work and any modifications or additions to that Work or Derivative Works
47 | thereof, that is intentionally submitted to Licensor for inclusion in the Work
48 | by the copyright owner or by an individual or Legal Entity authorized to submit
49 | on behalf of the copyright owner. For the purposes of this definition,
50 | “submitted” means any form of electronic, verbal, or written communication sent
51 | to the Licensor or its representatives, including but not limited to
52 | communication on electronic mailing lists, source code control systems, and
53 | issue tracking systems that are managed by, or on behalf of, the Licensor for
54 | the purpose of discussing and improving the Work, but excluding communication
55 | that is conspicuously marked or otherwise designated in writing by the copyright
56 | owner as “Not a Contribution.”
57 |
58 | “Contributor” shall mean Licensor and any individual or Legal Entity on behalf
59 | of whom a Contribution has been received by Licensor and subsequently
60 | incorporated within the Work.
61 |
62 | #### 2. Grant of Copyright License
63 |
64 | Subject to the terms and conditions of this License, each Contributor hereby
65 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
66 | irrevocable copyright license to reproduce, prepare Derivative Works of,
67 | publicly display, publicly perform, sublicense, and distribute the Work and such
68 | Derivative Works in Source or Object form.
69 |
70 | #### 3. Grant of Patent License
71 |
72 | Subject to the terms and conditions of this License, each Contributor hereby
73 | grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
74 | irrevocable (except as stated in this section) patent license to make, have
75 | made, use, offer to sell, sell, import, and otherwise transfer the Work, where
76 | such license applies only to those patent claims licensable by such Contributor
77 | that are necessarily infringed by their Contribution(s) alone or by combination
78 | of their Contribution(s) with the Work to which such Contribution(s) was
79 | submitted. If You institute patent litigation against any entity (including a
80 | cross-claim or counterclaim in a lawsuit) alleging that the Work or a
81 | Contribution incorporated within the Work constitutes direct or contributory
82 | patent infringement, then any patent licenses granted to You under this License
83 | for that Work shall terminate as of the date such litigation is filed.
84 |
85 | #### 4. Redistribution
86 |
87 | You may reproduce and distribute copies of the Work or Derivative Works thereof
88 | in any medium, with or without modifications, and in Source or Object form,
89 | provided that You meet the following conditions:
90 |
91 | - **(a)** You must give any other recipients of the Work or Derivative Works a copy of
92 | this License; and
93 | - **(b)** You must cause any modified files to carry prominent notices stating that You
94 | changed the files; and
95 | - **(c)** You must retain, in the Source form of any Derivative Works that You distribute,
96 | all copyright, patent, trademark, and attribution notices from the Source form
97 | of the Work, excluding those notices that do not pertain to any part of the
98 | Derivative Works; and
99 | - **(d)** If the Work includes a “NOTICE” text file as part of its distribution, then any
100 | Derivative Works that You distribute must include a readable copy of the
101 | attribution notices contained within such NOTICE file, excluding those notices
102 | that do not pertain to any part of the Derivative Works, in at least one of the
103 | following places: within a NOTICE text file distributed as part of the
104 | Derivative Works; within the Source form or documentation, if provided along
105 | with the Derivative Works; or, within a display generated by the Derivative
106 | Works, if and wherever such third-party notices normally appear. The contents of
107 | the NOTICE file are for informational purposes only and do not modify the
108 | License. You may add Your own attribution notices within Derivative Works that
109 | You distribute, alongside or as an addendum to the NOTICE text from the Work,
110 | provided that such additional attribution notices cannot be construed as
111 | modifying the License.
112 |
113 | You may add Your own copyright statement to Your modifications and may provide
114 | additional or different license terms and conditions for use, reproduction, or
115 | distribution of Your modifications, or for any such Derivative Works as a whole,
116 | provided Your use, reproduction, and distribution of the Work otherwise complies
117 | with the conditions stated in this License.
118 |
119 | #### 5. Submission of Contributions
120 |
121 | Unless You explicitly state otherwise, any Contribution intentionally submitted
122 | for inclusion in the Work by You to the Licensor shall be under the terms and
123 | conditions of this License, without any additional terms or conditions.
124 | Notwithstanding the above, nothing herein shall supersede or modify the terms of
125 | any separate license agreement you may have executed with Licensor regarding
126 | such Contributions.
127 |
128 | #### 6. Trademarks
129 |
130 | This License does not grant permission to use the trade names, trademarks,
131 | service marks, or product names of the Licensor, except as required for
132 | reasonable and customary use in describing the origin of the Work and
133 | reproducing the content of the NOTICE file.
134 |
135 | #### 7. Disclaimer of Warranty
136 |
137 | Unless required by applicable law or agreed to in writing, Licensor provides the
138 | Work (and each Contributor provides its Contributions) on an “AS IS” BASIS,
139 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
140 | including, without limitation, any warranties or conditions of TITLE,
141 | NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
142 | solely responsible for determining the appropriateness of using or
143 | redistributing the Work and assume any risks associated with Your exercise of
144 | permissions under this License.
145 |
146 | #### 8. Limitation of Liability
147 |
148 | In no event and under no legal theory, whether in tort (including negligence),
149 | contract, or otherwise, unless required by applicable law (such as deliberate
150 | and grossly negligent acts) or agreed to in writing, shall any Contributor be
151 | liable to You for damages, including any direct, indirect, special, incidental,
152 | or consequential damages of any character arising as a result of this License or
153 | out of the use or inability to use the Work (including but not limited to
154 | damages for loss of goodwill, work stoppage, computer failure or malfunction, or
155 | any and all other commercial damages or losses), even if such Contributor has
156 | been advised of the possibility of such damages.
157 |
158 | #### 9. Accepting Warranty or Additional Liability
159 |
160 | While redistributing the Work or Derivative Works thereof, You may choose to
161 | offer, and charge a fee for, acceptance of support, warranty, indemnity, or
162 | other liability obligations and/or rights consistent with this License. However,
163 | in accepting such obligations, You may act only on Your own behalf and on Your
164 | sole responsibility, not on behalf of any other Contributor, and only if You
165 | agree to indemnify, defend, and hold each Contributor harmless for any liability
166 | incurred by, or claims asserted against, such Contributor by reason of your
167 | accepting any such warranty or additional liability.
168 |
169 | _END OF TERMS AND CONDITIONS_
170 |
171 | ### APPENDIX: How to apply the Apache License to your work
172 |
173 | To apply the Apache License to your work, attach the following boilerplate
174 | notice, with the fields enclosed by brackets `[]` replaced with your own
175 | identifying information. (Don't include the brackets!) The text should be
176 | enclosed in the appropriate comment syntax for the file format. We also
177 | recommend that a file or class name and description of purpose be included on
178 | the same “printed page” as the copyright notice for easier identification within
179 | third-party archives.
180 |
181 | Copyright 2024 Nighty3098
182 |
183 | Licensed under the Apache License, Version 2.0 (the "License");
184 | you may not use this file except in compliance with the License.
185 | You may obtain a copy of the License at
186 |
187 | http://www.apache.org/licenses/LICENSE-2.0
188 |
189 | Unless required by applicable law or agreed to in writing, software
190 | distributed under the License is distributed on an "AS IS" BASIS,
191 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
192 | See the License for the specific language governing permissions and
193 | limitations under the License.
194 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Tech Support Discord server
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
Installing
20 |
21 |
22 | ```
23 | git clone https://github.com/SDashS/SDash
24 | cd SDash/app
25 | python3 -m venv SDash
26 | source SDash/bin/activate
27 | pip3 install -r ../requirements.txt
28 | ```
29 |
30 |
31 |
Run server
32 |
33 |
34 | > [!IMPORTANT]
35 | > This service has been tested on Arch, Debian, Ubuntu, Fedora based systems
36 |
37 | ```
38 | python3 server.py
39 | ```
40 |
41 | Using docker
42 |
43 | ```
44 | docker pull nighty3098/sdash
45 | ```
46 |
47 | Run server
48 |
49 | ```
50 | docker run nighty3098/sdash
51 | ```
52 |
53 |
54 |
Usage
55 | Use:
Shift +
C to open the command palette on PC
56 |
57 |
Screenshots
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 |
2 |
Security Policy
3 |
Supported Versions
4 |
Only Latest Version is Supported
5 |
6 | Reporting a Vulnerability:
7 | I. Add Title
8 | II. Add Description
9 | III. Add Screen
10 |
11 |
Contacts
12 |
13 |
14 |
15 |
16 |
17 |
Thanks <3
18 |
19 |
--------------------------------------------------------------------------------
/app/__pycache__/config.cpython-312.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nighty3098/SDash/1d7291940072403b47b504740b30f1f03c5846b3/app/__pycache__/config.cpython-312.pyc
--------------------------------------------------------------------------------
/app/__pycache__/func.cpython-312.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nighty3098/SDash/1d7291940072403b47b504740b30f1f03c5846b3/app/__pycache__/func.cpython-312.pyc
--------------------------------------------------------------------------------
/app/__pycache__/get_info.cpython-312.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nighty3098/SDash/1d7291940072403b47b504740b30f1f03c5846b3/app/__pycache__/get_info.cpython-312.pyc
--------------------------------------------------------------------------------
/app/__pycache__/routes.cpython-312.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nighty3098/SDash/1d7291940072403b47b504740b30f1f03c5846b3/app/__pycache__/routes.cpython-312.pyc
--------------------------------------------------------------------------------
/app/__pycache__/server.cpython-312.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nighty3098/SDash/1d7291940072403b47b504740b30f1f03c5846b3/app/__pycache__/server.cpython-312.pyc
--------------------------------------------------------------------------------
/app/config.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import os
3 | from logging.config import dictConfig
4 |
5 | from flask import Flask
6 |
7 | app = Flask(__name__)
8 |
9 | app_version = "0.3.6"
10 |
11 | logging.basicConfig(
12 | encoding="utf-8",
13 | datefmt="%m/%d/%Y %I:%M:%S %p",
14 | level=logging.INFO,
15 | format="%(asctime)s | %(levelname)s | %(name)s | %(threadName)s : %(message)s"
16 | )
17 |
--------------------------------------------------------------------------------
/app/func.py:
--------------------------------------------------------------------------------
1 | from subprocess import DEVNULL, PIPE, Popen
2 |
3 |
4 | def convert_seconds_to_hhmm(seconds):
5 | hours, minutes = divmod(seconds, 3600)
6 | return f"{hours:02}:{minutes // 60:02}"
7 |
8 |
9 | def truncate_string(s, max_length):
10 | return s if len(s) <= max_length else f"{s[:max_length - 3]}..."
11 |
12 |
13 | def run_command(command):
14 | process = Popen(
15 | command, stdout=PIPE, universal_newlines=True, shell=True, stderr=DEVNULL
16 | )
17 | return process.communicate()[0].strip()
18 |
--------------------------------------------------------------------------------
/app/get_info.py:
--------------------------------------------------------------------------------
1 | import platform
2 | import socket
3 | import sys
4 | import time
5 | from os import environ, path
6 | from subprocess import DEVNULL, PIPE, Popen
7 |
8 | import psutil
9 | from func import truncate_string
10 |
11 |
12 | def run_command(command):
13 | """Run a shell command and return the output."""
14 | with Popen(command, shell=True, stdout=PIPE, stderr=DEVNULL) as proc:
15 | output, _ = proc.communicate()
16 | return output.decode().strip()
17 |
18 |
19 | def get_open_ports_and_services():
20 | connections = psutil.net_connections(kind="inet")
21 | open_ports = {}
22 |
23 | for conn in connections:
24 | _, localPort = conn.laddr
25 | pid = conn.pid
26 |
27 | if pid is not None:
28 | try:
29 | process = psutil.Process(pid)
30 | service_name = process.name()
31 | username = process.username()
32 | status = "Running" # Default status if no exceptions occur
33 | open_ports[localPort] = {
34 | "service": service_name,
35 | "user": username,
36 | "status": status,
37 | }
38 | except psutil.NoSuchProcess:
39 | open_ports[localPort] = {
40 | "service": "Unknown service",
41 | "user": "Unknown user",
42 | "status": "No such process",
43 | }
44 | except Exception as e:
45 | open_ports[localPort] = {
46 | "service": "Error retrieving service",
47 | "user": "Unknown user",
48 | "status": f"Error: {str(e)}",
49 | }
50 |
51 | return open_ports
52 |
53 |
54 | def get_uptime():
55 | """Get system uptime."""
56 | try:
57 | if platform.system() == "Linux":
58 | with open("/proc/uptime", "r") as f:
59 | uptime_seconds = float(f.readline().split()[0])
60 | return f"{round(uptime_seconds // 86400)} days {round(uptime_seconds % 86400 // 3600)} hours {round(uptime_seconds % 3600 // 60)} minutes"
61 | elif platform.system() == "Windows":
62 | return run_command(
63 | "net stats workstation | findstr /C:'Statistics since'"
64 | ) # Windows uptime command
65 | elif platform.system() == "Darwin": # macOS
66 | return run_command("uptime") # macOS uptime command
67 | else:
68 | return "Unsupported OS for uptime retrieval."
69 | except Exception:
70 | return "Unsupported OS for uptime retrieval"
71 |
72 |
73 | def get_ip_address():
74 | """Get the local IP address."""
75 | try:
76 | with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
77 | s.connect(("8.8.8.8", 80))
78 | return s.getsockname()[0]
79 | except Exception:
80 | return "Unknown IP"
81 |
82 |
83 | def os_name():
84 | """Get the OS name."""
85 | try:
86 | if platform.system() == "Linux":
87 | os_file = "/etc/os-release"
88 | if path.isfile(os_file):
89 | return (
90 | run_command(f"grep 'PRETTY_NAME' {os_file}")
91 | .replace("PRETTY_NAME=", "")
92 | .replace('"', "")
93 | )
94 | elif platform.system() == "Windows":
95 | return run_command("ver") # Windows version command
96 | elif platform.system() == "Darwin":
97 | return run_command("sw_vers -productName") # macOS version command
98 | return "Unknown OS"
99 | except Exception:
100 | return "Unknown OS"
101 |
102 | def model_info():
103 | """Get model information."""
104 | try:
105 | if platform.system() == "Linux":
106 | product_info = run_command(
107 | "cat /sys/devices/virtual/dmi/id/product_name"
108 | ).strip()
109 | version_info = run_command(
110 | "cat /sys/devices/virtual/dmi/id/product_version"
111 | ).strip()
112 | return f"{product_info} {version_info}" if version_info else product_info
113 | elif platform.system() == "Windows":
114 | return run_command("wmic csproduct get name") # Windows model command
115 | elif platform.system() == "Darwin":
116 | return run_command(
117 | "system_profiler SPHardwareDataType | awk '/Model Name:/ {print $3, $4}'"
118 | )
119 | return "Unknown model"
120 | except Exception:
121 | return "Unknown model"
122 |
123 |
124 | def fetch_cpu_info():
125 | """Fetch CPU information."""
126 | try:
127 | if platform.system() == "Linux":
128 | cpu_info = run_command(
129 | "cat /proc/cpuinfo | grep 'model name' | uniq | cut -d: -f2"
130 | )
131 | cpu_max_freq = (
132 | int(
133 | run_command("cat /sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq")
134 | )
135 | / 1000
136 | )
137 | cpu_freq_info = (
138 | f"{cpu_max_freq:.3f} MHz"
139 | if cpu_max_freq < 1000
140 | else f"{cpu_max_freq / 1000:.3f} GHz"
141 | )
142 | return f"{cpu_info} @ {cpu_freq_info}"
143 | elif platform.system() == "Windows":
144 | return run_command("wmic cpu get name")
145 | elif platform.system() == "Darwin":
146 | return run_command("sysctl -n machdep.cpu.brand_string")
147 | return "Unknown CPU"
148 | except Exception:
149 | return "Unknown CPU"
150 |
151 |
152 | def gpu_info():
153 | """Fetch GPU information."""
154 | try:
155 | if platform.system() == "Darwin":
156 | return run_command(
157 | "system_profiler SPDisplaysDataType | awk '/Chipset Model:/ {print $3, $4, $5, $6, $7}'"
158 | ).strip()
159 | elif platform.system() == "Linux":
160 | return truncate_string(
161 | run_command("lspci | grep -i vga").split(":")[2].split("(")[0].strip(),
162 | 50,
163 | )
164 | elif platform.system() == "Windows":
165 | return run_command("wmic path win32_videocontroller get name")
166 |
167 | else:
168 | return "Unknown GPU"
169 |
170 | except Exception:
171 | return "Unknown GPU"
172 |
173 |
174 | def fetch_arch():
175 | """Fetch architecture information."""
176 | arch = platform.machine()
177 | return f"{arch}"
178 |
--------------------------------------------------------------------------------
/app/routes.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import os
3 | import platform
4 | import subprocess
5 | import time
6 | from datetime import datetime
7 | from logging.config import dictConfig
8 |
9 | import psutil
10 | import pynvml
11 | from config import app, app_version, dictConfig
12 | from flask import Flask, jsonify, redirect, render_template, request
13 | from func import convert_seconds_to_hhmm
14 | from get_info import (fetch_arch, fetch_cpu_info, get_ip_address,
15 | get_open_ports_and_services, get_uptime, gpu_info,
16 | model_info, os_name)
17 |
18 | prev_net_io = psutil.net_io_counters()
19 | prev_time = time.time()
20 |
21 |
22 | @app.route("/api/date", methods=["GET"])
23 | def get_server_date():
24 | current_time = datetime.now().strftime("%H:%M")
25 | current_date = datetime.now().strftime("%d %b %y")
26 | return jsonify({"current_time": current_time, "current_date": current_date})
27 |
28 |
29 | @app.route("/api/version")
30 | def get_version():
31 | return jsonify(version=app_version)
32 |
33 |
34 | @app.route("/api/open-ports")
35 | def open_ports():
36 | ports = get_open_ports_and_services()
37 | return jsonify(ports)
38 |
39 |
40 | @app.route("/api/usage")
41 | def usage():
42 | global prev_net_io, prev_time
43 |
44 | cpu_usage = psutil.cpu_percent(interval=1)
45 | ram = psutil.virtual_memory()
46 | disk = psutil.disk_usage("/")
47 |
48 | net_io = psutil.net_io_counters()
49 | current_time = time.time()
50 | elapsed_time = current_time - prev_time
51 |
52 | bytes_recv = net_io.bytes_recv - prev_net_io.bytes_recv
53 | bytes_sent = net_io.bytes_sent - prev_net_io.bytes_sent
54 |
55 | prev_net_io, prev_time = net_io, current_time
56 |
57 | speed_recv = bytes_recv / elapsed_time / 1024 # kB/s
58 | speed_sent = bytes_sent / elapsed_time / 1024 # kB/s
59 |
60 | return jsonify(
61 | cpu_usage=cpu_usage,
62 | ram_usage=ram.percent,
63 | ram_total=ram.total,
64 | ram_used=ram.used,
65 | disk_usage=disk.percent,
66 | disk_total=disk.total,
67 | disk_used=disk.used,
68 | net_recv=speed_recv,
69 | net_sent=speed_sent,
70 | cpu_freq=psutil.cpu_freq().current,
71 | )
72 |
73 |
74 | @app.route("/api/system_info")
75 | def get_info():
76 | return jsonify(
77 | device_uptime=get_uptime(),
78 | device_ip=get_ip_address(),
79 | sys_platform=os_name(),
80 | device_name=os.uname().nodename,
81 | sys_model=model_info(),
82 | sys_cpu=fetch_cpu_info(),
83 | sys_gpu=gpu_info(),
84 | cpu_arch=fetch_arch(),
85 | )
86 |
87 |
88 | @app.route("/api/cpu_temp")
89 | def cpu_temp():
90 | try:
91 | temperatures = psutil.sensors_temperatures().get("coretemp", [])
92 | if not temperatures:
93 | raise ValueError("No temperature data available for coretemp")
94 |
95 | avg_temp = sum(temp.current for temp in temperatures) / len(temperatures)
96 | return jsonify(cpu_temp=avg_temp, cpu_freq=psutil.cpu_freq().current)
97 | except Exception as e:
98 | return jsonify(cpu_temp="N/A", error=str(e))
99 |
100 |
101 | @app.route("/api/gpu_temp")
102 | def gpu_temp():
103 | try:
104 | pynvml.nvmlInit()
105 | device_count = pynvml.nvmlDeviceGetCount()
106 | if device_count > 0:
107 | device = pynvml.nvmlDeviceGetHandleByIndex(0)
108 | return jsonify(
109 | gpu_temp=pynvml.nvmlDeviceGetTemperature(
110 | device, pynvml.NVML_TEMPERATURE_GPU
111 | ),
112 | gpu_freq=pynvml.nvmlDeviceGetUtilizationRates(device).gpu,
113 | )
114 | return jsonify(gpu_temp="None", gpu_freq="None")
115 | except Exception as e:
116 | return jsonify(gpu_temp="None", gpu_freq="None", error=str(e))
117 |
118 |
119 | @app.route("/api/disk_temperature", methods=["GET"])
120 | def disk_temperature():
121 | disk_temp = get_disk_temperature()
122 | return jsonify(disk_temp) if disk_temp else jsonify(None)
123 |
124 |
125 | @app.route("/api/battery", methods=["GET"])
126 | def battery_status():
127 | battery = psutil.sensors_battery()
128 | if battery:
129 | charge = battery.percent
130 | plugged = battery.power_plugged
131 | time_to_full = (
132 | convert_seconds_to_hhmm(battery.secsleft)
133 | if plugged and battery.secsleft != psutil.POWER_TIME_UNKNOWN
134 | else None
135 | )
136 | time_to_empty = (
137 | convert_seconds_to_hhmm(battery.secsleft)
138 | if not plugged and battery.secsleft != psutil.POWER_TIME_UNKNOWN
139 | else None
140 | )
141 |
142 | return jsonify(
143 | charge=charge,
144 | plugged=plugged,
145 | time_to_full=time_to_full,
146 | time_to_empty=time_to_empty,
147 | )
148 | return jsonify(charge=None, plugged=None, time_to_full=None, time_to_empty=None)
149 |
150 |
151 | @app.route("/api/user_ip")
152 | def get_user_ip():
153 | ip_address = request.headers.get("X-Forwarded-For", request.remote_addr)
154 | return jsonify({"ip": ip_address})
155 |
156 |
157 | @app.route("/navigate", methods=["POST"])
158 | def navigate():
159 | page = request.form["page"]
160 | return f"Navigating to {page} page"
161 |
162 |
163 | @app.route("/get_os")
164 | def get_os_color():
165 | os_name_str = os_name()
166 | return jsonify({"os_name": os_name_str})
167 |
168 |
169 | @app.route("/")
170 | def index():
171 | return render_template("index.html")
172 |
173 |
174 | @app.route("/api/actions/reboot", methods=["POST"])
175 | def reboot_server():
176 | os.system("systemctl reboot")
177 |
178 | return "Rebooting..."
179 |
180 |
181 | @app.route("/api/actions/shutdown", methods=["POST"])
182 | def shutdown_server():
183 | os.system("systemctl poweroff")
184 |
185 | return "Shutting down..."
186 |
187 |
188 | @app.route("/api/actions/sleep", methods=["POST"])
189 | def sleep_server():
190 | os.system("systemctl suspend")
191 |
192 | return "Sleeping..."
193 |
194 |
195 | @app.errorhandler(404)
196 | def not_found(error):
197 | app.logger.warning("404 PAGE")
198 | return render_template("error.html"), 404
199 |
--------------------------------------------------------------------------------
/app/server.py:
--------------------------------------------------------------------------------
1 | import os
2 | import platform
3 | import subprocess
4 | import time
5 |
6 | import psutil
7 | from config import dictConfig
8 | from flask import Flask, jsonify, render_template, request
9 | from get_info import (fetch_cpu_info, get_ip_address, get_uptime, gpu_info,
10 | model_info, os_name)
11 | from routes import app
12 | from setproctitle import getproctitle, setproctitle
13 |
14 | if __name__ == "__main__":
15 | setproctitle("SDash")
16 | app.logger.critical("!!! New User logging in")
17 | app.run(debug=True, host=get_ip_address())
18 |
--------------------------------------------------------------------------------
/app/static/bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nighty3098/SDash/1d7291940072403b47b504740b30f1f03c5846b3/app/static/bg.png
--------------------------------------------------------------------------------
/app/static/css/404.css:
--------------------------------------------------------------------------------
1 | * {
2 | -webkit-box-sizing: border-box;
3 | box-sizing: border-box;
4 | }
5 |
6 | body {
7 | background-color: #222831;
8 | padding: 0;
9 | margin: 0;
10 | }
11 |
12 | #notfound {
13 | position: relative;
14 | height: 100vh;
15 | }
16 |
17 | #notfound .notfound {
18 | position: absolute;
19 | left: 50%;
20 | top: 50%;
21 | -webkit-transform: translate(-50%, -50%);
22 | -ms-transform: translate(-50%, -50%);
23 | transform: translate(-50%, -50%);
24 | }
25 |
26 | .notfound {
27 | max-width: 520px;
28 | width: 100%;
29 | line-height: 1.4;
30 | text-align: center;
31 | }
32 |
33 | .notfound .notfound-404 {
34 | position: relative;
35 | height: 240px;
36 | }
37 |
38 | .notfound .notfound-404 h1 {
39 | font-family: montserrat, sans-serif;
40 | position: absolute;
41 | left: 50%;
42 | top: 50%;
43 | -webkit-transform: translate(-50%, -50%);
44 | -ms-transform: translate(-50%, -50%);
45 | transform: translate(-50%, -50%);
46 | font-size: 252px;
47 | font-weight: 900;
48 | margin: 0;
49 | color: #d5d9d6;
50 | text-transform: uppercase;
51 | letter-spacing: -40px;
52 | margin-left: -20px;
53 | }
54 |
55 | .notfound .notfound-404 h1 > span {
56 | text-shadow: -8px 0 0 #fff;
57 | }
58 |
59 | .notfound .notfound-404 h3 {
60 | font-family: cabin, sans-serif;
61 | position: relative;
62 | font-size: 16px;
63 | font-weight: 700;
64 | text-transform: uppercase;
65 | color: #fff;
66 | margin: 0;
67 | letter-spacing: 3px;
68 | padding-left: 6px;
69 | }
70 |
71 | .notfound h2 {
72 | font-family: cabin, sans-serif;
73 | font-size: 20px;
74 | font-weight: 400;
75 | text-transform: uppercase;
76 | color: #d5d9d6;
77 | margin-top: 0;
78 | margin-bottom: 25px;
79 | }
80 |
81 | @media only screen and (max-width: 767px) {
82 | .notfound .notfound-404 {
83 | height: 200px;
84 | }
85 |
86 | .notfound .notfound-404 h1 {
87 | font-size: 200px;
88 | }
89 | }
90 |
91 | @media only screen and (max-width: 480px) {
92 | .notfound .notfound-404 {
93 | height: 162px;
94 | }
95 |
96 | .notfound .notfound-404 h1 {
97 | font-size: 162px;
98 | height: 150px;
99 | line-height: 162px;
100 | }
101 |
102 | .notfound h2 {
103 | font-size: 16px;
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/app/static/css/style.css:
--------------------------------------------------------------------------------
1 | @import url("https://fonts.googleapis.com/css2?family=M+PLUS+Rounded+1c:wght@100;300;400;500;700;800;900&family=Pacifico&display=swap");
2 |
3 | :root {
4 | --bg: #2f3541;
5 | --bg2: #3d4452;
6 | --fg: #cad3f5;
7 | --accent: #9abfe5;
8 | --accent-hover: #9abfe5;
9 | --accent-pressed: #babbf1;
10 | --critical: #ed8796;
11 | --warning: #e5c890;
12 | --normal: #a6da95;
13 | }
14 |
15 | html {
16 | width: 100%;
17 | height: auto;
18 | background-image: url("../bg.png");
19 | display: flex;
20 | flex-direction: column;
21 |
22 | scrollbar-color: var(--accent-hover) var(--bg);
23 | scrollbar-arrow-color: var(--bg) var(--bg);
24 |
25 | background-attachment: fixed;
26 | background-size: cover;
27 | background-repeat: no-repeat;
28 | }
29 |
30 | body {
31 | width: 100%;
32 | height: 100%;
33 | overflow-y: scroll;
34 | margin: 0;
35 | padding: 0;
36 | font-family: "M PLUS Rounded 1c", system-ui;
37 | color: var(--accent-hover);
38 | font-size: small;
39 | animation: fadeIn 0.5s ease;
40 | display: flex;
41 | flex-direction: column;
42 | justify-content: center;
43 | }
44 |
45 | h1 {
46 | font-size: xx-large;
47 | }
48 |
49 | h3 {
50 | font-size: 13px;
51 | font-weight: bold;
52 | font-family: "M PLUS Rounded 1c", system-ui;
53 | }
54 |
55 | .calendar_block {
56 | display: flex;
57 | flex-direction: column;
58 | align-items: center;
59 | text-align: center;
60 | margin-top: 5%;
61 | margin-bottom: 5%;
62 | width: 100%;
63 | height: 100%;
64 | }
65 |
66 | .clock {
67 | font-size: 100px;
68 | margin: 0px;
69 | }
70 |
71 | .date {
72 | font-size: 25px;
73 | margin: 0px;
74 | }
75 |
76 | .summary_data h1 {
77 | margin: 0%;
78 | color: var(--bg);
79 | }
80 |
81 | .center {
82 | display: flex;
83 | justify-content: center;
84 | align-items: center;
85 | }
86 |
87 | .align-left {
88 | text-align: left;
89 | }
90 |
91 | .modal {
92 | display: none;
93 | position: fixed;
94 | z-index: 10000;
95 | left: 0;
96 | top: 0;
97 | width: 100%;
98 | height: 100%;
99 | overflow: auto;
100 | background-color: rgba(47, 53, 65, 0.4);
101 | animation: fadeOut 1s ease;
102 | }
103 |
104 | .modal-content {
105 | background-color: rgba(47, 53, 65, 1);
106 | margin: 3% auto;
107 | border: 2px solid var(--bg2);
108 | width: 50%;
109 | padding: 20px;
110 | border-radius: 20px;
111 | animation: slideInDown 1s ease;
112 | }
113 |
114 | @media (max-width: 1000px) {
115 | .modal-content {
116 | margin: 10% auto;
117 | width: 70%;
118 | }
119 | }
120 |
121 | .close-button {
122 | color: #aaa;
123 | float: right;
124 | font-size: 28px;
125 | font-weight: bold;
126 | cursor: pointer;
127 | transition: color 0.3s ease;
128 | }
129 |
130 | .close-button:hover,
131 | .close-button:focus {
132 | color: var(--accent-hover);
133 | text-decoration: none;
134 | cursor: pointer;
135 | }
136 |
137 | .tab-buttons {
138 | margin-top: 40px;
139 | display: flex;
140 | flex-direction: row;
141 | justify-content: center;
142 | }
143 |
144 | .tab-button {
145 | background-color: var(--bg2);
146 | border-radius: 16px;
147 | box-shadow: 0 4px 40px rgba(47, 53, 65, 0.1);
148 | border: 2px solid var(--bg2);
149 | color: var(--fg);
150 | outline: none;
151 | cursor: pointer;
152 | padding: 10px 20px;
153 | margin: 1%;
154 | width: 20%;
155 | transition:
156 | background-color 0.6s ease,
157 | color 0.6s ease,
158 | transform 0.6s ease;
159 | }
160 |
161 | .tab-button.active {
162 | color: var(--bg);
163 | background-color: var(--accent-hover);
164 | }
165 |
166 | .tab-button:hover {
167 | transform: scale(1.05);
168 | }
169 |
170 | .context-menu ul {
171 | list-style: none;
172 | padding: 0;
173 | margin: 0;
174 | }
175 |
176 | @media (max-width: 1000px) {
177 | .tab-buttons {
178 | flex-direction: column;
179 | }
180 |
181 | .tab-button {
182 | width: 100%;
183 | }
184 | }
185 |
186 | .context-menu li {
187 | padding: 8px 12px;
188 | cursor: pointer;
189 | transition: background-color 0.6s ease;
190 | }
191 |
192 | .context-menu li:hover {
193 | background-color: #f2f2f2;
194 | }
195 |
196 | .progress-bar {
197 | width: 80%;
198 | height: 30px;
199 | background-color: var(--bg);
200 | border-radius: 10px;
201 | overflow: hidden;
202 | animation: fadeIn 0.5s ease;
203 | display: block;
204 | text-align: left;
205 | }
206 |
207 | .progress {
208 | font-family: "M PLUS Rounded 1c", system-ui;
209 | width: 0%;
210 | height: 100%;
211 | border-radius: 10px;
212 | background-color: var(--accent-hover);
213 | transition: width 0.5s ease-in-out;
214 | }
215 |
216 | .info-table {
217 | font-family: "M PLUS Rounded 1c", system-ui;
218 | border-collapse: collapse;
219 | font-size: 16px;
220 | animation: fadeIn 0.5s ease;
221 | }
222 |
223 | .info-table td {
224 | padding: 10px;
225 | text-align: left;
226 | vertical-align: middle;
227 | transition: background-color 0.6s ease;
228 | }
229 |
230 | .control {
231 | font-family: "M PLUS Rounded 1c", system-ui;
232 | height: 100vh;
233 | display: flex;
234 | animation: fadeIn 0.5s ease;
235 | }
236 |
237 | .p_buttons {
238 | display: flex;
239 | flex-direction: column;
240 | margin-left: 0.5vh;
241 | margin-right: 0.5vh;
242 | }
243 |
244 | .power_button {
245 | height: 12vh;
246 | aspect-ratio: 1 / 1;
247 | border: 2px solid var(--bg2);
248 | border-radius: 10px;
249 | display: block;
250 | margin: 1vh;
251 | align-items: center;
252 | justify-content: center;
253 | transition:
254 | transform 0.3s,
255 | background-color 0.3s,
256 | fill 0.5s;
257 | background-color: rgba(47, 53, 65, 0.4);
258 | backdrop-filter: blur(10px);
259 | animation:
260 | fadeIn 0.5s ease,
261 | slideInDown 1s ease;
262 | }
263 |
264 | .power_button svg {
265 | height: 5vh;
266 | aspect-ratio: 1 / 1;
267 | }
268 |
269 | .power_button:hover {
270 | transform: scale(1.05);
271 | background-color: var(--accent-hover);
272 | }
273 |
274 | .power_button:hover svg path {
275 | fill: var(--bg);
276 | }
277 |
278 | .power_button svg path {
279 | fill: var(--accent-hover);
280 | }
281 |
282 | .content-title {
283 | font-family: "Pacifico", cursive;
284 | font-size: 70px;
285 | font-weight: bold;
286 | animation: fadeIn 0.5s ease;
287 | margin-top: 2%;
288 | margin-bottom: 2%;
289 | }
290 |
291 | p {
292 | font-size: small;
293 | animation: fadeIn 0.5s ease;
294 | }
295 |
296 | .button {
297 | background-color: rgba(47, 53, 65, 0.4);
298 | border-radius: 16px;
299 | box-shadow: 0 4px 40px rgba(47, 53, 65, 0.1);
300 | backdrop-filter: blur(8.3px);
301 | border: 2px solid var(--bg2);
302 | color: var(--fg);
303 |
304 | font-family: "M PLUS Rounded 1c", system-ui;
305 | font-weight: 400;
306 | font-style: normal;
307 | display: inline-block;
308 | height: 3vh;
309 | width: 30%;
310 | margin-left: 5px;
311 | margin-right: 5px;
312 | margin-top: 0.5vh;
313 | font-size: small;
314 | cursor: pointer;
315 | transition:
316 | background-color 0.7s ease,
317 | color 0.7s ease,
318 | transform 0.6s ease;
319 | }
320 |
321 | .button:hover {
322 | background-color: var(--accent-hover);
323 | transform: scale(1.05);
324 | color: var(--bg);
325 | }
326 |
327 | .button:active {
328 | color: var(--bg);
329 | background-color: var(--accent-pressed);
330 | }
331 |
332 | @keyframes fadeIn {
333 | from {
334 | opacity: 0;
335 | }
336 | to {
337 | opacity: 1;
338 | }
339 | }
340 |
341 | @keyframes slideInLeft {
342 | from {
343 | transform: translateX(-15%);
344 | opacity: 0;
345 | }
346 | to {
347 | transform: translateX(0);
348 | opacity: 1;
349 | }
350 | }
351 |
352 | @keyframes slideInDown {
353 | from {
354 | transform: translateY(-15%);
355 | opacity: 0;
356 | }
357 | to {
358 | transform: translateY(0);
359 | opacity: 1;
360 | }
361 | }
362 |
363 | @keyframes slideInUp {
364 | from {
365 | transform: translateY(15%);
366 | opacity: 0;
367 | }
368 | to {
369 | transform: translateY(0);
370 | opacity: 1;
371 | }
372 | }
373 |
374 | @media (max-height: 992px) {
375 | .button {
376 | height: 6vh;
377 | }
378 | }
379 |
380 | @media (min-height: 1300px) {
381 | .button {
382 | height: 3vh;
383 | }
384 | }
385 |
386 | .dock {
387 | align-items: right;
388 | display: flex;
389 | margin-top: 10px;
390 | width: 100%;
391 | height: auto;
392 | justify-content: right;
393 | z-index: 56;
394 | animation: fadeIn 0.5s ease;
395 | }
396 |
397 | .dock button {
398 | width: 50px;
399 | height: 50px;
400 | margin-right: 20px;
401 | }
402 |
403 | .tab-content {
404 | display: none;
405 | transition: opacity 1s ease;
406 | }
407 |
408 | .tab-content.active {
409 | display: block;
410 | opacity: 1;
411 | animation: fadeIn 0.5s ease;
412 | }
413 |
414 | .tab-content.hidden {
415 | opacity: 0;
416 | }
417 |
418 | .container {
419 | font-family: "M PLUS Rounded 1c", system-ui;
420 | margin-top: 1%;
421 | margin-bottom: 1%;
422 | padding-top: 1%;
423 | padding-bottom: 1%;
424 | width: 80%;
425 | height: auto;
426 | margin-left: 10%;
427 | border-radius: 30px;
428 | background-color: transparent;
429 | animation: fadeIn 0.5s ease;
430 | display: flex;
431 | flex-direction: column;
432 | justify-content: center;
433 | }
434 |
435 | .summary_data {
436 | background-color: rgba(47, 53, 65, 0.6);
437 | border-radius: 16px;
438 | box-shadow: 10 40px 40px rgba(47, 53, 65, 0.4);
439 | backdrop-filter: blur(8.3px);
440 | border: 1px solid var(--bg2);
441 | font-family: "M PLUS Rounded 1c", system-ui;
442 | transition:
443 | transform 0.5s,
444 | opacity 0.5s,
445 | box-shadow 0.5s;
446 | display: flex;
447 | aspect-ratio: 2 / 1.2;
448 | flex-direction: column;
449 | align-items: center;
450 | padding: 4%;
451 | margin: 2% 0%;
452 | opacity: 0;
453 | animation: fadeIn 2s ease forwards;
454 | }
455 |
456 | .summary_data_text {
457 | align-items: center;
458 | align-content: center;
459 | }
460 |
461 | .system_info {
462 | background-color: rgba(47, 53, 65, 0.4);
463 | border-radius: 16px;
464 | box-shadow: 0 4px 40px rgba(47, 53, 65, 0.1);
465 | backdrop-filter: blur(8.3px);
466 | border: 2px solid var(--bg2);
467 | width: 90%;
468 | padding: 5%;
469 | text-align: center;
470 | justify-content: center;
471 | display: flex;
472 | flex-direction: row;
473 | transition: backdrop 0.5s;
474 | animation:
475 | slideInDown 1s ease,
476 | fadeIn 0.5s ease;
477 | }
478 |
479 | .os_icon {
480 | height: 100%;
481 | width: auto;
482 | }
483 |
484 | .summary_data div {
485 | margin-bottom: auto;
486 | }
487 |
488 | .summary_data svg {
489 | width: 20%;
490 | }
491 |
492 | .summary_data svg path {
493 | fill: var(--accent-hover);
494 | }
495 |
496 | .summary_data span {
497 | font-size: 13px;
498 | font-weight: bold;
499 | }
500 |
501 | .cards {
502 | display: grid;
503 | grid-template-columns: 50% 50%;
504 | grid-gap: 2%;
505 | align-items: center;
506 | justify-content: center;
507 | font-family: "M PLUS Rounded 1c", system-ui;
508 | animation: fadeIn 0.5s ease;
509 | }
510 |
511 | .summary_data:hover {
512 | transform: scale(1.05);
513 | }
514 |
515 | .main-cards {
516 | display: flex;
517 | justify-content: center;
518 | flex-direction: column;
519 | align-items: center;
520 | text-align: center;
521 | }
522 |
523 | .settings {
524 | display: flex;
525 | justify-content: center;
526 | flex-direction: column;
527 | align-items: center;
528 | text-align: center;
529 | }
530 |
531 | .settings h1 {
532 | font-size: 70px;
533 | margin: 0px;
534 | }
535 |
536 | .settings h3 {
537 | font-size: 20px;
538 | margin: 0px;
539 | }
540 |
541 | .settings svg {
542 | aspect-ratio: 1/1;
543 | width: 30px;
544 | fill: var(--accent);
545 | margin: 0px;
546 | margin-left: 30px;
547 | transition: fill 0.6s ease;
548 | }
549 |
550 | .settings svg:hover {
551 | fill: var(--fg);
552 | }
553 |
554 | .port-container {
555 | display: flex;
556 | flex-wrap: wrap;
557 | gap: 30px;
558 | align-items: center;
559 | justify-content: center;
560 |
561 | width: 100%;
562 | max-width: 100%;
563 | overflow-y: auto;
564 | overflow-x: hidden;
565 | margin: 0px;
566 | animation: slideInDown 1s ease;
567 | }
568 |
569 | .port-block {
570 | background-color: rgba(47, 53, 65, 0.4);
571 | border-radius: 16px;
572 | backdrop-filter: blur(8.3px);
573 | border: 2px solid var(--bg2);
574 |
575 | display: flex;
576 | flex-direction: column;
577 | justify-content: center;
578 | align-content: center;
579 |
580 | padding: 2%;
581 | margin: 0px;
582 |
583 | width: 30%;
584 | height: auto;
585 |
586 | line-height: 1%;
587 |
588 | transition: transform 0.6s ease;
589 | animation: fadeIn 0.5s ease;
590 | }
591 |
592 | .port-block p {
593 | font-size: medium;
594 | }
595 |
596 | .port-block:hover {
597 | transform: scale(1.05);
598 | }
599 |
600 | .port-block img {
601 | width: 8%;
602 | }
603 |
604 | .subcontent {
605 | align-items: center;
606 | align-content: center;
607 | margin: 0px;
608 | justify-content: center;
609 | }
610 |
611 | @media screen and (max-width: 700px) {
612 | .main-cards {
613 | margin-top: 10%;
614 | margin-bottom: 10%;
615 | width: 100%;
616 | }
617 |
618 | .summary_data {
619 | width: 90%;
620 | aspect-ratio: auto;
621 | height: auto;
622 | padding-top: 10%;
623 | padding-bottom: 10%;
624 | }
625 |
626 | .summary_data svg {
627 | width: 12%;
628 | }
629 |
630 | .button {
631 | width: 50%;
632 | }
633 |
634 | .system_info {
635 | margin-top: 5%;
636 | width: 100%;
637 | flex-direction: column;
638 | text-align: center;
639 | }
640 |
641 | .subcontent {
642 | width: 100%;
643 | }
644 |
645 | .os_icon {
646 | width: 60%;
647 | }
648 |
649 | .p_buttons {
650 | margin-top: 20%;
651 | }
652 |
653 | select.button {
654 | height: 50px;
655 | }
656 |
657 | .cards {
658 | width: 100%;
659 | grid-template-columns: 100%;
660 | grid-gap: 0%;
661 | }
662 |
663 | .port-block {
664 | width: 100%;
665 | }
666 | }
667 |
668 | @media screen and (max-width: 1300px) and (min-width: 700px) {
669 | .system_info {
670 | width: 70%;
671 | text-align: center;
672 | }
673 |
674 | select.button {
675 | animation: slideInDown 1s ease;
676 | }
677 |
678 | .button {
679 | animation: slideInUp 1s ease;
680 | }
681 |
682 | .summary_data svg {
683 | width: 10%;
684 | }
685 |
686 | .port-block {
687 | width: 100%;
688 | }
689 |
690 | .cards {
691 | grid-template-columns: 100%;
692 | grid-gap: 0%;
693 | }
694 |
695 | .summary_data {
696 | aspect-ratio: 2/1;
697 | height: auto;
698 | }
699 | }
700 |
701 | @media screen and (min-width: 1300px) {
702 | .system_info {
703 | width: 50%;
704 | }
705 |
706 | .summary_data svg {
707 | width: 17%;
708 | }
709 | }
710 |
711 | @media screen and (min-width: 2000px) {
712 | .summary_data svg {
713 | width: 15%;
714 | }
715 | }
716 |
--------------------------------------------------------------------------------
/app/static/icons/arrow.svg:
--------------------------------------------------------------------------------
1 |
2 |
16 |
18 |
36 |
40 |
45 |
48 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/app/static/icons/battery-bolt.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
19 |
37 |
41 |
46 |
49 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/app/static/icons/battery-exclamation.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
19 |
37 |
41 |
46 |
49 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/app/static/icons/battery_full.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
19 |
37 |
41 |
46 |
49 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/app/static/icons/cpu.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
19 |
37 |
41 |
46 |
49 |
54 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/app/static/icons/down.svg:
--------------------------------------------------------------------------------
1 |
2 |
14 |
16 |
34 |
38 |
43 |
46 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/app/static/icons/off.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
19 |
37 |
41 |
46 |
49 |
51 |
54 |
58 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/app/static/icons/ram.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
37 |
38 |
41 |
42 |
46 |
47 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/app/static/icons/reboot.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
19 |
37 |
41 |
46 |
49 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/app/static/icons/service.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/app/static/icons/sleep.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
36 |
37 |
41 |
42 |
47 |
48 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/app/static/icons/storage.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
19 |
37 |
41 |
46 |
49 |
50 | ic_fluent_storage_24_regular
52 | Created with Sketch.
54 |
61 |
66 |
70 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/app/static/icons/temp.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
19 |
37 |
41 |
46 |
49 |
50 | ic_fluent_temperature_24_regular
52 | Created with Sketch.
54 |
61 |
66 |
70 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/app/static/icons/up.svg:
--------------------------------------------------------------------------------
1 |
2 |
14 |
16 |
34 |
37 |
41 |
43 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/app/static/js/check_updates.js:
--------------------------------------------------------------------------------
1 | async function fetchCurrentVersion() {
2 | const response = await fetch('/api/version');
3 | if (!response.ok) {
4 | throw new Error(`HTTP error while fetching current version! status: ${response.status}`);
5 | }
6 |
7 | const versionData = await response.json();
8 | if (!versionData || !versionData.version) {
9 | throw new Error('Current version is undefined or missing from the response.');
10 | }
11 | return versionData.version;
12 | }
13 |
14 | async function fetchLatestRelease() {
15 | const apiUrl = `https://api.github.com/repos/Nighty3098/SDash/releases/latest`;
16 | const response = await fetch(apiUrl, {
17 | method: 'GET',
18 | headers: {
19 | 'Accept': 'application/vnd.github.v3+json',
20 | }
21 | });
22 |
23 | if (!response.ok) {
24 | throw new Error(`HTTP error while fetching release data! status: ${response.status}`);
25 | }
26 |
27 | const releaseData = await response.json();
28 | if (!releaseData || !releaseData.tag_name) {
29 | throw new Error('Latest version is undefined or missing from the response.');
30 | }
31 | return releaseData.tag_name;
32 | }
33 |
34 | function compareVersions(v1, v2) {
35 | const v1Parts = v1.split('.').map(Number);
36 | const v2Parts = v2.split('.').map(Number);
37 |
38 | for (let i = 0; i < Math.max(v1Parts.length, v2Parts.length); i++) {
39 | const v1Part = v1Parts[i] || 0;
40 | const v2Part = v2Parts[i] || 0;
41 |
42 | if (v1Part > v2Part) return 1;
43 | if (v1Part < v2Part) return -1;
44 | }
45 | return 0;
46 | }
47 |
48 | async function checkLatestRelease() {
49 | try {
50 | const currentVersion = await fetchCurrentVersion();
51 | const latestVersion = await fetchLatestRelease();
52 |
53 | handleVersionComparison(latestVersion, currentVersion);
54 |
55 | } catch (error) {
56 | console.error('Error while checking for updates:', error);
57 | }
58 | }
59 |
60 | function handleVersionComparison(latestVersion, currentVersion) {
61 | const comparisonResult = compareVersions(latestVersion, currentVersion);
62 |
63 | if (comparisonResult > 0) {
64 | alert(`New version available: ${latestVersion}. Current version: ${currentVersion}.`);
65 | } else if (comparisonResult < 0) {
66 | alert(`You are using an incompatible version: ${currentVersion}. Latest version: ${latestVersion}.`);
67 | } else {
68 | alert(`You are using the latest version: ${currentVersion}.`);
69 | }
70 | }
71 |
72 | async function showVersion() {
73 | const versionResponse = await fetch('/api/version');
74 |
75 | if (!versionResponse.ok) {
76 | throw new Error(`HTTP error while fetching current version! status: ${versionResponse.status}`);
77 | }
78 | else {
79 | const versionData = await versionResponse.json();
80 | document.getElementById("version").innerHTML = versionData.version;
81 | }
82 |
83 | }
84 |
85 | // showVersion();
86 |
--------------------------------------------------------------------------------
/app/static/js/indicators.js:
--------------------------------------------------------------------------------
1 | const colors = {
2 | bg: "#142943",
3 | fg: "#cad3f5",
4 | accent: "#9ABFE5",
5 | accent_hover: "#9ABFE5",
6 | critical: "#ed8796",
7 | warning: "#e5c890",
8 | normal: "#a6da95"
9 | };
10 |
11 | const updateIndicators = async () => {
12 | try {
13 | const [usage, cpuTemp, gpuTemp, userIP, serverDate] = await Promise.all([
14 | fetch('/api/usage').then(response => response.json()),
15 | fetch('/api/cpu_temp').then(response => response.json()),
16 | fetch('/api/gpu_temp').then(response => response.json()),
17 | fetch('/api/user_ip').then(response => response.json()),
18 | fetch('/api/date').then(response => response.json())
19 | ]);
20 |
21 | updateProgressBars(usage);
22 | updateSummaryTexts(usage);
23 | updateNetworkSpeeds(usage);
24 | updateCpuTemperature(cpuTemp);
25 | updateGpuTemperature(gpuTemp);
26 | getUserIp(userIP);
27 | getServerDate(serverDate);
28 | } catch (error) {
29 | console.error('Error updating indicators:', error);
30 | }
31 | };
32 |
33 | const getUserIp = (userIP) => {
34 | const user_ip = userIP.ip;
35 |
36 | console.debug("User IP: " + user_ip);
37 | };
38 |
39 | const updateProgressBars = (usage) => {
40 | const progressElements = {
41 | cpu: document.getElementById('cpu-progress'),
42 | ram: document.getElementById('ram-progress'),
43 | disk: document.getElementById('disk-progress')
44 | };
45 |
46 | progressElements.cpu.style.width = `${usage.cpu_usage}%`;
47 | if (usage.cpu_usage > 90) {
48 | progressElements.cpu.style.backgroundColor = colors.critical;
49 | } else if (usage.cpu_usage > 70) {
50 | progressElements.cpu.style.backgroundColor = colors.warning;
51 | } else {
52 | progressElements.cpu.style.backgroundColor = colors.accent_hover;
53 | }
54 |
55 | progressElements.ram.style.width = `${usage.ram_usage}%`;
56 | if (usage.ram_usage > 90) {
57 | progressElements.ram.style.backgroundColor = colors.critical;
58 | } else if (usage.ram_usage > 80) {
59 | progressElements.ram.style.backgroundColor = colors.warning;
60 | } else {
61 | progressElements.ram.style.backgroundColor = colors.accent_hover;
62 | }
63 |
64 | progressElements.disk.style.width = `${usage.disk_usage}%`;
65 | if (usage.disk_usage > 90) {
66 | progressElements.disk.style.backgroundColor = colors.critical;
67 | } else if (usage.disk_usage > 80) {
68 | progressElements.disk.style.backgroundColor = colors.warning;
69 | } else {
70 | progressElements.disk.style.backgroundColor = colors.accent_hover;
71 | }
72 | };
73 |
74 | const updateSummaryTexts = (usage) => {
75 | document.getElementById('cpu-value').textContent = `CPU: ${usage.cpu_usage.toFixed(2)}%`;
76 | document.getElementById('ram-value').textContent = `RAM: ${(usage.ram_used / (1024 ** 3)).toFixed(1)}GB / ${(usage.ram_total / (1024 ** 3)).toFixed(1)}GB - ${usage.ram_usage.toFixed(1)}%`;
77 | document.getElementById('disk-value').textContent = `Disk: ${(usage.disk_used / (1024 ** 3)).toFixed(1)}GB / ${(usage.disk_total / (1024 ** 3)).toFixed(1)}GB - ${usage.disk_usage.toFixed(2)}%`;
78 | document.getElementById('summary_data_cpu_text').innerHTML = `CPU USAGE: ${usage.cpu_usage}%`;
79 | document.getElementById('summary_data_ram_text').innerHTML = `RAM USAGE: ${usage.ram_usage}%`;
80 | document.getElementById('summary_data_disk_text').innerHTML = `DISK USAGE: ${usage.disk_usage}%`;
81 |
82 | console.debug("CPU USAGE: " + usage.cpu_usage);
83 | console.debug("RAM USAGE: " + usage.ram_usage);
84 | console.debug("DISK USAGE: " + usage.disk_usage);
85 | };
86 |
87 | const updateNetworkSpeeds = (usage) => {
88 | document.getElementById('upload_speed').innerHTML = `UPLOAD SPEED: ${usage.net_sent.toFixed(2)}kb/s`;
89 | document.getElementById('download_speed').innerHTML = `DOWNLOAD SPEED: ${usage.net_recv.toFixed(2)}kb/s`;
90 | };
91 |
92 | const updateCpuTemperature = (cpuTemp) => {
93 | document.getElementById('summary_data_cpu_temp_text').innerHTML = `CPU: ${cpuTemp.cpu_temp.toFixed(1)}°C - ${(cpuTemp.cpu_freq / 1000).toFixed(1)}GHz`;
94 | if (cpuTemp.cpu_temp.toFixed(0) > 45) {
95 | document.getElementById('summary_data_cpu_temp_text').style.color = colors.warning;
96 | } else if (cpuTemp.cpu_temp.toFixed(0) > 60) {
97 | document.getElementById('summary_data_cpu_temp_text').style.color = colors.critical;
98 | } else {
99 | document.getElementById('summary_data_cpu_temp_text').style.color = colors.accent_hover;
100 | }
101 |
102 | console.debug(`CPU TEMP: ${cpuTemp.cpu_temp.toFixed(1)}°C - ${(cpuTemp.cpu_freq / 1000).toFixed(1)}GHz`);
103 | };
104 |
105 | const updateGpuTemperature = (gpuTemp) => {
106 | if (gpuTemp.gpu_temp != "None") {
107 | document.getElementById('summary_data_gpu_temp_text').innerHTML = "GPU: " + gpuTemp.gpu_temp + "°C - " + gpuTemp.gpu_freq + "MHz";
108 | if (gpuTemp.gpu_temp > 45) {
109 | document.getElementById('summary_data_gpu_temp_text').style.color = colors.warning;
110 | } else if (gpuTemp.gpu_temp > 60) {
111 | document.getElementById('summary_data_gpu_temp_text').style.color = colors.critical;
112 | } else {
113 | document.getElementById('summary_data_gpu_temp_text').style.color = colors.accent_hover;
114 | }
115 | }
116 | else {
117 | document.getElementById('summary_data_gpu_temp_text').style.display = "None";
118 | }
119 |
120 | console.debug("GPU: " + gpuTemp.gpu_temp + "°C - " + gpuTemp.gpu_freq + "MHz");
121 | };
122 |
123 | const updateSystemInfo = async () => {
124 | try {
125 | const data = await fetch('/api/system_info').then(response => response.json());
126 | const systemInfoElements = {
127 | uptime: document.getElementById('device_uptime'),
128 | ip: document.getElementById('device_ip'),
129 | platform: document.getElementById('platform'),
130 | deviceName: document.getElementById('device_name'),
131 | model: document.getElementById('model'),
132 | cpu: document.getElementById('cpu'),
133 | cpuArch: document.getElementById('cpu_arch'),
134 | gpu: document.getElementById('gpu'),
135 | };
136 |
137 | systemInfoElements.platform.innerText = data.sys_platform;
138 | systemInfoElements.uptime.innerHTML = data.device_uptime;
139 | systemInfoElements.ip.innerText = data.device_ip;
140 | systemInfoElements.deviceName.innerText = data.device_name;
141 | systemInfoElements.model.innerText = data.sys_model;
142 | systemInfoElements.cpu.innerText = data.sys_cpu;
143 | systemInfoElements.gpu.innerText = data.sys_gpu;
144 | systemInfoElements.cpuArch.innerText = data.cpu_arch;
145 | } catch (error) {
146 | console.error('Error updating system info:', error);
147 | }
148 | };
149 |
150 |
151 | const fetchBatteryStatus = async () => {
152 | try {
153 | const response = await fetch('/api/battery');
154 | if (!response.ok) {
155 | throw new Error('Network response was not ok');
156 | }
157 |
158 | const data = await response.json();
159 | const chargeElement = document.getElementById('charge');
160 | const batteryProgress = document.getElementById('battery-progress');
161 | const battery_block = document.getElementById('battery-progress-bar');
162 |
163 | const battery_icon = document.getElementById('battery-icon');
164 | const battery_unknown_icon = document.getElementById('unknown_battery');
165 | const battery_charging_icon = document.getElementById('battery-charging-icon');
166 |
167 | const charge = data.charge !== null ? data.charge.toFixed(2) : null;
168 | const status = data.plugged ? "Charging" : "Not Charging";
169 | const backgroundColor = determineBackgroundColor(data.plugged, charge);
170 |
171 | if (charge !== null) {
172 | console.debug(`BATTERY: ${charge}%`);
173 | chargeElement.innerHTML = `BATTERY: ${charge}% ${status}`;
174 | batteryProgress.style.width = `${charge}%`;
175 | battery_unknown_icon.style.display = "None";
176 |
177 | if (status == "Charging") {
178 | battery_icon.style.display = "None";
179 | battery_charging_icon.style.display = "normal";
180 | }
181 | else {
182 | battery_icon.style.display = "normal";
183 | battery_charging_icon.style.display = "None";
184 | }
185 |
186 | } else {
187 | chargeElement.style.display = "normal";
188 | batteryProgress.style.display = "None";
189 | battery_block.style.display = "None";
190 | battery_icon.style.display = "None";
191 | battery_charging_icon.style.display = "None";
192 | battery_unknown_icon.style.display = "normal";
193 | battery_unknown_icon.style.width = "35%";
194 | chargeElement.innerHTML = `Battery not found`;
195 | }
196 |
197 | batteryProgress.style.backgroundColor = backgroundColor;
198 | } catch (error) {
199 | console.error('Error fetching battery status:', error);
200 | }
201 | };
202 |
203 | const determineBackgroundColor = (plugged, charge) => {
204 | if (plugged) {
205 | return colors.normal;
206 | } else if (charge < 15) {
207 | return colors.critical;
208 | } else if (charge < 20) {
209 | return colors.warning;
210 | } else {
211 | return colors.accent_hover;
212 | }
213 | };
214 |
215 | const fetchOpenPorts = async () => {
216 | const portContainer = document.getElementById('port-container');
217 | portContainer.innerHTML = '';
218 |
219 | try {
220 | const response = await fetch('/api/open-ports');
221 | if (!response.ok) {
222 | throw new Error('Network response was not ok');
223 | }
224 | const data = await response.json();
225 | console.debug(data);
226 |
227 | for (const port in data) {
228 | const portBlock = createPortBlock({
229 | port: port,
230 | service: data[port].service,
231 | user: data[port].user
232 | });
233 | portContainer.appendChild(portBlock);
234 | }
235 | } catch (error) {
236 | console.error('Error fetching open ports:', error);
237 | }
238 | };
239 |
240 | function createPortBlock(port) {
241 | const portBlock = document.createElement('div');
242 | portBlock.classList.add('port-block');
243 |
244 | const portLabel = document.createElement('p');
245 | portLabel.textContent = `Port: ${port.port}`;
246 |
247 | const serviceLabel = document.createElement('p');
248 | serviceLabel.textContent = `${port.service}`;
249 |
250 | const userLabel = document.createElement('p');
251 | userLabel.textContent = `User: ${port.user}`;
252 |
253 | portBlock.appendChild(serviceLabel);
254 | portBlock.appendChild(portLabel);
255 | portBlock.appendChild(userLabel);
256 |
257 | return portBlock;
258 | };
259 |
260 | function getServerDate(serverDate) {
261 | if (serverDate && serverDate.current_time && serverDate.current_date) {
262 | const clock_block = document.getElementById("clock");
263 | const date_block = document.getElementById("date");
264 |
265 | clock_block.textContent = serverDate.current_time;
266 | date_block.textContent = serverDate.current_date;
267 | } else {
268 | console.error('Invalid server date response:', serverDate);
269 | }
270 | }
271 |
272 | fetchOpenPorts();
273 |
274 | setInterval(fetchBatteryStatus, 1000);
275 | setInterval(updateIndicators, 1000);
276 | setInterval(updateSystemInfo, 1000);
277 | setInterval(fetchOpenPorts, 10000);
278 | setInterval(getServerDate, 1000);
279 |
--------------------------------------------------------------------------------
/app/static/js/os_badge.js:
--------------------------------------------------------------------------------
1 | const osImageMap = {
2 | 'endeavour': '../static/logo/linux.svg',
3 | 'manjaro': '../static/logo/manjaro.svg',
4 | 'arch': '../static/logo/arch.svg',
5 | 'cent': '../static/logo/centos.svg',
6 | 'fedora': '../static/logo/fedora.svg',
7 | 'mac': '../static/logo/mac.svg',
8 | 'windows': '../static/logo/windows.svg',
9 | 'debian': '../static/logo/debian.svg',
10 | 'hat': '../static/logo/hat.svg',
11 | 'mint': '../static/logo/mint.svg',
12 | 'suse': '../static/logo/suse.svg',
13 | 'ubuntu': '../static/logo/ubuntu.svg'
14 | };
15 |
16 | const fetchSystemInfo = async () => {
17 | try {
18 | const response = await fetch('/api/system_info');
19 | if (!response.ok) {
20 | throw new Error('Network response was not ok');
21 | }
22 |
23 | const data = await response.json();
24 | const osName = data.sys_platform.toLowerCase();
25 |
26 | setOSImage(osName);
27 |
28 | } catch (error) {
29 | console.error('Error fetching system info:', error);
30 | }
31 | };
32 |
33 | const setOSImage = (osName) => {
34 | const osIconElement = document.getElementById('os_icon');
35 |
36 | for (const key in osImageMap) {
37 | if (osName.includes(key)) {
38 | osIconElement.src = osImageMap[key];
39 | return;
40 | }
41 | }
42 |
43 | osIconElement.src = '../static/logo/os.svg';
44 | };
45 |
46 | fetchSystemInfo();
47 |
--------------------------------------------------------------------------------
/app/static/js/tabs.js:
--------------------------------------------------------------------------------
1 | document.addEventListener('DOMContentLoaded', function() {
2 | const modal = document.getElementById('modal');
3 | const closeButton = document.getElementsByClassName('close-button')[0];
4 | const tabButtons = document.getElementsByClassName('tab-button');
5 | const openModalButton = document.getElementById('open-modal-button');
6 |
7 | document.addEventListener('keydown', function(event) {
8 | if (event.shiftKey && event.key === 'C') {
9 | modal.style.display = 'block';
10 | }
11 | });
12 |
13 | openModalButton.addEventListener('click', function() {
14 | modal.style.display = 'block';
15 | });
16 |
17 | closeButton.addEventListener('click', function() {
18 | modal.style.display = 'none';
19 | });
20 |
21 | window.addEventListener('click', function(event) {
22 | if (event.target == modal) {
23 | modal.style.display = 'none';
24 | }
25 | });
26 |
27 | Array.from(tabButtons).forEach(button => {
28 | button.addEventListener('click', function() {
29 | const activeButton = document.querySelector('.tab-button.active');
30 | activeButton.classList.remove('active');
31 | this.classList.add('active');
32 |
33 | const tab = this.getAttribute('data-tab');
34 | switchTab(tab);
35 | });
36 | });
37 |
38 | function switchTab(tab) {
39 | const tabContents = document.getElementsByClassName('tab-content');
40 | Array.from(tabContents).forEach(content => {
41 | if (content.id === tab) {
42 | content.classList.add('active');
43 | content.classList.remove('hidden');
44 | } else {
45 | content.classList.remove('active');
46 | content.classList.add('hidden');
47 | }
48 | });
49 | }
50 |
51 | switchTab('monitor');
52 | });
53 |
--------------------------------------------------------------------------------
/app/static/logo/arch.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
14 |
32 | arch
34 |
38 |
39 |
--------------------------------------------------------------------------------
/app/static/logo/centos.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
14 |
32 |
33 |
37 |
38 |
--------------------------------------------------------------------------------
/app/static/logo/debian.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
14 |
32 |
33 |
37 |
38 |
--------------------------------------------------------------------------------
/app/static/logo/fedora.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
14 |
32 |
33 |
37 |
38 |
--------------------------------------------------------------------------------
/app/static/logo/hat.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
14 |
32 |
33 |
37 |
38 |
--------------------------------------------------------------------------------
/app/static/logo/linux.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
14 |
32 | linux
34 |
38 |
39 |
--------------------------------------------------------------------------------
/app/static/logo/mac.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
14 |
32 |
33 |
37 |
38 |
--------------------------------------------------------------------------------
/app/static/logo/manjaro.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
14 |
31 |
32 |
50 | manjaro
52 |
59 |
60 |
--------------------------------------------------------------------------------
/app/static/logo/mint.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
14 |
32 | linux-mint
34 |
38 |
39 |
--------------------------------------------------------------------------------
/app/static/logo/os.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
14 |
32 |
33 |
37 |
38 |
--------------------------------------------------------------------------------
/app/static/logo/suse.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
14 |
32 |
33 |
37 |
38 |
--------------------------------------------------------------------------------
/app/static/logo/ubuntu.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
14 |
32 |
33 |
37 |
38 |
--------------------------------------------------------------------------------
/app/static/logo/windows.svg:
--------------------------------------------------------------------------------
1 |
2 |
12 |
14 |
32 |
33 |
37 |
38 |
--------------------------------------------------------------------------------
/app/templates/error.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | 404 Error
9 |
10 |
90 |
149 |
150 |
154 |
155 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
Oops! Page not found
166 | 4 0 4
167 |
168 |
we are sorry, but the page you requested was not found
169 |
170 |
171 |
172 |
176 |
185 |
192 |
193 |
194 |
--------------------------------------------------------------------------------
/docker-compose.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | services:
3 | sdash:
4 | image: nighty3098/sdash:latest
5 | ports:
6 | - '5000:5000'
7 | restart: always
8 |
--------------------------------------------------------------------------------
/imgs/img_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nighty3098/SDash/1d7291940072403b47b504740b30f1f03c5846b3/imgs/img_1.png
--------------------------------------------------------------------------------
/imgs/img_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nighty3098/SDash/1d7291940072403b47b504740b30f1f03c5846b3/imgs/img_2.png
--------------------------------------------------------------------------------
/imgs/img_3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nighty3098/SDash/1d7291940072403b47b504740b30f1f03c5846b3/imgs/img_3.png
--------------------------------------------------------------------------------
/imgs/img_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nighty3098/SDash/1d7291940072403b47b504740b30f1f03c5846b3/imgs/img_4.png
--------------------------------------------------------------------------------
/imgs/img_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nighty3098/SDash/1d7291940072403b47b504740b30f1f03c5846b3/imgs/img_5.png
--------------------------------------------------------------------------------
/imgs/img_6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nighty3098/SDash/1d7291940072403b47b504740b30f1f03c5846b3/imgs/img_6.png
--------------------------------------------------------------------------------
/poetry.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand.
2 |
3 | [[package]]
4 | name = "blinker"
5 | version = "1.8.2"
6 | description = "Fast, simple object-to-object and broadcast signaling"
7 | optional = false
8 | python-versions = ">=3.8"
9 | files = [
10 | {file = "blinker-1.8.2-py3-none-any.whl", hash = "sha256:1779309f71bf239144b9399d06ae925637cf6634cf6bd131104184531bf67c01"},
11 | {file = "blinker-1.8.2.tar.gz", hash = "sha256:8f77b09d3bf7c795e969e9486f39c2c5e9c39d4ee07424be2bc594ece9642d83"},
12 | ]
13 |
14 | [[package]]
15 | name = "click"
16 | version = "8.1.7"
17 | description = "Composable command line interface toolkit"
18 | optional = false
19 | python-versions = ">=3.7"
20 | files = [
21 | {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
22 | {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
23 | ]
24 |
25 | [package.dependencies]
26 | colorama = {version = "*", markers = "platform_system == \"Windows\""}
27 |
28 | [[package]]
29 | name = "colorama"
30 | version = "0.4.6"
31 | description = "Cross-platform colored terminal text."
32 | optional = false
33 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
34 | files = [
35 | {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
36 | {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
37 | ]
38 |
39 | [[package]]
40 | name = "flask"
41 | version = "3.0.3"
42 | description = "A simple framework for building complex web applications."
43 | optional = false
44 | python-versions = ">=3.8"
45 | files = [
46 | {file = "flask-3.0.3-py3-none-any.whl", hash = "sha256:34e815dfaa43340d1d15a5c3a02b8476004037eb4840b34910c6e21679d288f3"},
47 | {file = "flask-3.0.3.tar.gz", hash = "sha256:ceb27b0af3823ea2737928a4d99d125a06175b8512c445cbd9a9ce200ef76842"},
48 | ]
49 |
50 | [package.dependencies]
51 | blinker = ">=1.6.2"
52 | click = ">=8.1.3"
53 | itsdangerous = ">=2.1.2"
54 | Jinja2 = ">=3.1.2"
55 | Werkzeug = ">=3.0.0"
56 |
57 | [package.extras]
58 | async = ["asgiref (>=3.2)"]
59 | dotenv = ["python-dotenv"]
60 |
61 | [[package]]
62 | name = "itsdangerous"
63 | version = "2.2.0"
64 | description = "Safely pass data to untrusted environments and back."
65 | optional = false
66 | python-versions = ">=3.8"
67 | files = [
68 | {file = "itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef"},
69 | {file = "itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173"},
70 | ]
71 |
72 | [[package]]
73 | name = "jinja2"
74 | version = "3.1.4"
75 | description = "A very fast and expressive template engine."
76 | optional = false
77 | python-versions = ">=3.7"
78 | files = [
79 | {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"},
80 | {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"},
81 | ]
82 |
83 | [package.dependencies]
84 | MarkupSafe = ">=2.0"
85 |
86 | [package.extras]
87 | i18n = ["Babel (>=2.7)"]
88 |
89 | [[package]]
90 | name = "markupsafe"
91 | version = "3.0.2"
92 | description = "Safely add untrusted strings to HTML/XML markup."
93 | optional = false
94 | python-versions = ">=3.9"
95 | files = [
96 | {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"},
97 | {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"},
98 | {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"},
99 | {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"},
100 | {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"},
101 | {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"},
102 | {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"},
103 | {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"},
104 | {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"},
105 | {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"},
106 | {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"},
107 | {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"},
108 | {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"},
109 | {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"},
110 | {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"},
111 | {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"},
112 | {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"},
113 | {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"},
114 | {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"},
115 | {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"},
116 | {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"},
117 | {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"},
118 | {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"},
119 | {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"},
120 | {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"},
121 | {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"},
122 | {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"},
123 | {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"},
124 | {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"},
125 | {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"},
126 | {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"},
127 | {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"},
128 | {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"},
129 | {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"},
130 | {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"},
131 | {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"},
132 | {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"},
133 | {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"},
134 | {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"},
135 | {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"},
136 | {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"},
137 | {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"},
138 | {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"},
139 | {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"},
140 | {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"},
141 | {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"},
142 | {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"},
143 | {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"},
144 | {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"},
145 | {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"},
146 | {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a"},
147 | {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff"},
148 | {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13"},
149 | {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144"},
150 | {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29"},
151 | {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0"},
152 | {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0"},
153 | {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178"},
154 | {file = "MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f"},
155 | {file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"},
156 | {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"},
157 | ]
158 |
159 | [[package]]
160 | name = "psutil"
161 | version = "6.1.0"
162 | description = "Cross-platform lib for process and system monitoring in Python."
163 | optional = false
164 | python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
165 | files = [
166 | {file = "psutil-6.1.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:ff34df86226c0227c52f38b919213157588a678d049688eded74c76c8ba4a5d0"},
167 | {file = "psutil-6.1.0-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:c0e0c00aa18ca2d3b2b991643b799a15fc8f0563d2ebb6040f64ce8dc027b942"},
168 | {file = "psutil-6.1.0-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:000d1d1ebd634b4efb383f4034437384e44a6d455260aaee2eca1e9c1b55f047"},
169 | {file = "psutil-6.1.0-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:5cd2bcdc75b452ba2e10f0e8ecc0b57b827dd5d7aaffbc6821b2a9a242823a76"},
170 | {file = "psutil-6.1.0-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:045f00a43c737f960d273a83973b2511430d61f283a44c96bf13a6e829ba8fdc"},
171 | {file = "psutil-6.1.0-cp27-none-win32.whl", hash = "sha256:9118f27452b70bb1d9ab3198c1f626c2499384935aaf55388211ad982611407e"},
172 | {file = "psutil-6.1.0-cp27-none-win_amd64.whl", hash = "sha256:a8506f6119cff7015678e2bce904a4da21025cc70ad283a53b099e7620061d85"},
173 | {file = "psutil-6.1.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6e2dcd475ce8b80522e51d923d10c7871e45f20918e027ab682f94f1c6351688"},
174 | {file = "psutil-6.1.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:0895b8414afafc526712c498bd9de2b063deaac4021a3b3c34566283464aff8e"},
175 | {file = "psutil-6.1.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dcbfce5d89f1d1f2546a2090f4fcf87c7f669d1d90aacb7d7582addece9fb38"},
176 | {file = "psutil-6.1.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:498c6979f9c6637ebc3a73b3f87f9eb1ec24e1ce53a7c5173b8508981614a90b"},
177 | {file = "psutil-6.1.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d905186d647b16755a800e7263d43df08b790d709d575105d419f8b6ef65423a"},
178 | {file = "psutil-6.1.0-cp36-cp36m-win32.whl", hash = "sha256:6d3fbbc8d23fcdcb500d2c9f94e07b1342df8ed71b948a2649b5cb060a7c94ca"},
179 | {file = "psutil-6.1.0-cp36-cp36m-win_amd64.whl", hash = "sha256:1209036fbd0421afde505a4879dee3b2fd7b1e14fee81c0069807adcbbcca747"},
180 | {file = "psutil-6.1.0-cp37-abi3-win32.whl", hash = "sha256:1ad45a1f5d0b608253b11508f80940985d1d0c8f6111b5cb637533a0e6ddc13e"},
181 | {file = "psutil-6.1.0-cp37-abi3-win_amd64.whl", hash = "sha256:a8fb3752b491d246034fa4d279ff076501588ce8cbcdbb62c32fd7a377d996be"},
182 | {file = "psutil-6.1.0.tar.gz", hash = "sha256:353815f59a7f64cdaca1c0307ee13558a0512f6db064e92fe833784f08539c7a"},
183 | ]
184 |
185 | [package.extras]
186 | dev = ["black", "check-manifest", "coverage", "packaging", "pylint", "pyperf", "pypinfo", "pytest-cov", "requests", "rstcheck", "ruff", "sphinx", "sphinx_rtd_theme", "toml-sort", "twine", "virtualenv", "wheel"]
187 | test = ["pytest", "pytest-xdist", "setuptools"]
188 |
189 | [[package]]
190 | name = "pynvml"
191 | version = "11.5.3"
192 | description = "Python utilities for the NVIDIA Management Library"
193 | optional = false
194 | python-versions = ">=3.6"
195 | files = [
196 | {file = "pynvml-11.5.3-py3-none-any.whl", hash = "sha256:a5fba3ab14febda50d19dbda012ef62ae0aed45b7ccc07af0bc5be79223e450c"},
197 | {file = "pynvml-11.5.3.tar.gz", hash = "sha256:183d223ae487e5f00402d8da06c68c978ef8a9295793ee75559839c6ade7b229"},
198 | ]
199 |
200 | [[package]]
201 | name = "setproctitle"
202 | version = "1.3.3"
203 | description = "A Python module to customize the process title"
204 | optional = false
205 | python-versions = ">=3.7"
206 | files = [
207 | {file = "setproctitle-1.3.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:897a73208da48db41e687225f355ce993167079eda1260ba5e13c4e53be7f754"},
208 | {file = "setproctitle-1.3.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:8c331e91a14ba4076f88c29c777ad6b58639530ed5b24b5564b5ed2fd7a95452"},
209 | {file = "setproctitle-1.3.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bbbd6c7de0771c84b4aa30e70b409565eb1fc13627a723ca6be774ed6b9d9fa3"},
210 | {file = "setproctitle-1.3.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c05ac48ef16ee013b8a326c63e4610e2430dbec037ec5c5b58fcced550382b74"},
211 | {file = "setproctitle-1.3.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1342f4fdb37f89d3e3c1c0a59d6ddbedbde838fff5c51178a7982993d238fe4f"},
212 | {file = "setproctitle-1.3.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc74e84fdfa96821580fb5e9c0b0777c1c4779434ce16d3d62a9c4d8c710df39"},
213 | {file = "setproctitle-1.3.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9617b676b95adb412bb69645d5b077d664b6882bb0d37bfdafbbb1b999568d85"},
214 | {file = "setproctitle-1.3.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6a249415f5bb88b5e9e8c4db47f609e0bf0e20a75e8d744ea787f3092ba1f2d0"},
215 | {file = "setproctitle-1.3.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:38da436a0aaace9add67b999eb6abe4b84397edf4a78ec28f264e5b4c9d53cd5"},
216 | {file = "setproctitle-1.3.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:da0d57edd4c95bf221b2ebbaa061e65b1788f1544977288bdf95831b6e44e44d"},
217 | {file = "setproctitle-1.3.3-cp310-cp310-win32.whl", hash = "sha256:a1fcac43918b836ace25f69b1dca8c9395253ad8152b625064415b1d2f9be4fb"},
218 | {file = "setproctitle-1.3.3-cp310-cp310-win_amd64.whl", hash = "sha256:200620c3b15388d7f3f97e0ae26599c0c378fdf07ae9ac5a13616e933cbd2086"},
219 | {file = "setproctitle-1.3.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:334f7ed39895d692f753a443102dd5fed180c571eb6a48b2a5b7f5b3564908c8"},
220 | {file = "setproctitle-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:950f6476d56ff7817a8fed4ab207727fc5260af83481b2a4b125f32844df513a"},
221 | {file = "setproctitle-1.3.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:195c961f54a09eb2acabbfc90c413955cf16c6e2f8caa2adbf2237d1019c7dd8"},
222 | {file = "setproctitle-1.3.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f05e66746bf9fe6a3397ec246fe481096664a9c97eb3fea6004735a4daf867fd"},
223 | {file = "setproctitle-1.3.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b5901a31012a40ec913265b64e48c2a4059278d9f4e6be628441482dd13fb8b5"},
224 | {file = "setproctitle-1.3.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64286f8a995f2cd934082b398fc63fca7d5ffe31f0e27e75b3ca6b4efda4e353"},
225 | {file = "setproctitle-1.3.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:184239903bbc6b813b1a8fc86394dc6ca7d20e2ebe6f69f716bec301e4b0199d"},
226 | {file = "setproctitle-1.3.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:664698ae0013f986118064b6676d7dcd28fefd0d7d5a5ae9497cbc10cba48fa5"},
227 | {file = "setproctitle-1.3.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:e5119a211c2e98ff18b9908ba62a3bd0e3fabb02a29277a7232a6fb4b2560aa0"},
228 | {file = "setproctitle-1.3.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:417de6b2e214e837827067048f61841f5d7fc27926f2e43954567094051aff18"},
229 | {file = "setproctitle-1.3.3-cp311-cp311-win32.whl", hash = "sha256:6a143b31d758296dc2f440175f6c8e0b5301ced3b0f477b84ca43cdcf7f2f476"},
230 | {file = "setproctitle-1.3.3-cp311-cp311-win_amd64.whl", hash = "sha256:a680d62c399fa4b44899094027ec9a1bdaf6f31c650e44183b50d4c4d0ccc085"},
231 | {file = "setproctitle-1.3.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d4460795a8a7a391e3567b902ec5bdf6c60a47d791c3b1d27080fc203d11c9dc"},
232 | {file = "setproctitle-1.3.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:bdfd7254745bb737ca1384dee57e6523651892f0ea2a7344490e9caefcc35e64"},
233 | {file = "setproctitle-1.3.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:477d3da48e216d7fc04bddab67b0dcde633e19f484a146fd2a34bb0e9dbb4a1e"},
234 | {file = "setproctitle-1.3.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ab2900d111e93aff5df9fddc64cf51ca4ef2c9f98702ce26524f1acc5a786ae7"},
235 | {file = "setproctitle-1.3.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:088b9efc62d5aa5d6edf6cba1cf0c81f4488b5ce1c0342a8b67ae39d64001120"},
236 | {file = "setproctitle-1.3.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a6d50252377db62d6a0bb82cc898089916457f2db2041e1d03ce7fadd4a07381"},
237 | {file = "setproctitle-1.3.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:87e668f9561fd3a457ba189edfc9e37709261287b52293c115ae3487a24b92f6"},
238 | {file = "setproctitle-1.3.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:287490eb90e7a0ddd22e74c89a92cc922389daa95babc833c08cf80c84c4df0a"},
239 | {file = "setproctitle-1.3.3-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:4fe1c49486109f72d502f8be569972e27f385fe632bd8895f4730df3c87d5ac8"},
240 | {file = "setproctitle-1.3.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4a6ba2494a6449b1f477bd3e67935c2b7b0274f2f6dcd0f7c6aceae10c6c6ba3"},
241 | {file = "setproctitle-1.3.3-cp312-cp312-win32.whl", hash = "sha256:2df2b67e4b1d7498632e18c56722851ba4db5d6a0c91aaf0fd395111e51cdcf4"},
242 | {file = "setproctitle-1.3.3-cp312-cp312-win_amd64.whl", hash = "sha256:f38d48abc121263f3b62943f84cbaede05749047e428409c2c199664feb6abc7"},
243 | {file = "setproctitle-1.3.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:816330675e3504ae4d9a2185c46b573105d2310c20b19ea2b4596a9460a4f674"},
244 | {file = "setproctitle-1.3.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:68f960bc22d8d8e4ac886d1e2e21ccbd283adcf3c43136161c1ba0fa509088e0"},
245 | {file = "setproctitle-1.3.3-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:00e6e7adff74796ef12753ff399491b8827f84f6c77659d71bd0b35870a17d8f"},
246 | {file = "setproctitle-1.3.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53bc0d2358507596c22b02db079618451f3bd720755d88e3cccd840bafb4c41c"},
247 | {file = "setproctitle-1.3.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad6d20f9541f5f6ac63df553b6d7a04f313947f550eab6a61aa758b45f0d5657"},
248 | {file = "setproctitle-1.3.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c1c84beab776b0becaa368254801e57692ed749d935469ac10e2b9b825dbdd8e"},
249 | {file = "setproctitle-1.3.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:507e8dc2891021350eaea40a44ddd887c9f006e6b599af8d64a505c0f718f170"},
250 | {file = "setproctitle-1.3.3-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b1067647ac7aba0b44b591936118a22847bda3c507b0a42d74272256a7a798e9"},
251 | {file = "setproctitle-1.3.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2e71f6365744bf53714e8bd2522b3c9c1d83f52ffa6324bd7cbb4da707312cd8"},
252 | {file = "setproctitle-1.3.3-cp37-cp37m-win32.whl", hash = "sha256:7f1d36a1e15a46e8ede4e953abb104fdbc0845a266ec0e99cc0492a4364f8c44"},
253 | {file = "setproctitle-1.3.3-cp37-cp37m-win_amd64.whl", hash = "sha256:c9a402881ec269d0cc9c354b149fc29f9ec1a1939a777f1c858cdb09c7a261df"},
254 | {file = "setproctitle-1.3.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ff814dea1e5c492a4980e3e7d094286077054e7ea116cbeda138819db194b2cd"},
255 | {file = "setproctitle-1.3.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:accb66d7b3ccb00d5cd11d8c6e07055a4568a24c95cf86109894dcc0c134cc89"},
256 | {file = "setproctitle-1.3.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:554eae5a5b28f02705b83a230e9d163d645c9a08914c0ad921df363a07cf39b1"},
257 | {file = "setproctitle-1.3.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a911b26264dbe9e8066c7531c0591cfab27b464459c74385b276fe487ca91c12"},
258 | {file = "setproctitle-1.3.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2982efe7640c4835f7355fdb4da313ad37fb3b40f5c69069912f8048f77b28c8"},
259 | {file = "setproctitle-1.3.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df3f4274b80709d8bcab2f9a862973d453b308b97a0b423a501bcd93582852e3"},
260 | {file = "setproctitle-1.3.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:af2c67ae4c795d1674a8d3ac1988676fa306bcfa1e23fddb5e0bd5f5635309ca"},
261 | {file = "setproctitle-1.3.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:af4061f67fd7ec01624c5e3c21f6b7af2ef0e6bab7fbb43f209e6506c9ce0092"},
262 | {file = "setproctitle-1.3.3-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:37a62cbe16d4c6294e84670b59cf7adcc73faafe6af07f8cb9adaf1f0e775b19"},
263 | {file = "setproctitle-1.3.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a83ca086fbb017f0d87f240a8f9bbcf0809f3b754ee01cec928fff926542c450"},
264 | {file = "setproctitle-1.3.3-cp38-cp38-win32.whl", hash = "sha256:059f4ce86f8cc92e5860abfc43a1dceb21137b26a02373618d88f6b4b86ba9b2"},
265 | {file = "setproctitle-1.3.3-cp38-cp38-win_amd64.whl", hash = "sha256:ab92e51cd4a218208efee4c6d37db7368fdf182f6e7ff148fb295ecddf264287"},
266 | {file = "setproctitle-1.3.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c7951820b77abe03d88b114b998867c0f99da03859e5ab2623d94690848d3e45"},
267 | {file = "setproctitle-1.3.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5bc94cf128676e8fac6503b37763adb378e2b6be1249d207630f83fc325d9b11"},
268 | {file = "setproctitle-1.3.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f5d9027eeda64d353cf21a3ceb74bb1760bd534526c9214e19f052424b37e42"},
269 | {file = "setproctitle-1.3.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e4a8104db15d3462e29d9946f26bed817a5b1d7a47eabca2d9dc2b995991503"},
270 | {file = "setproctitle-1.3.3-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c32c41ace41f344d317399efff4cffb133e709cec2ef09c99e7a13e9f3b9483c"},
271 | {file = "setproctitle-1.3.3-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cbf16381c7bf7f963b58fb4daaa65684e10966ee14d26f5cc90f07049bfd8c1e"},
272 | {file = "setproctitle-1.3.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e18b7bd0898398cc97ce2dfc83bb192a13a087ef6b2d5a8a36460311cb09e775"},
273 | {file = "setproctitle-1.3.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:69d565d20efe527bd8a9b92e7f299ae5e73b6c0470f3719bd66f3cd821e0d5bd"},
274 | {file = "setproctitle-1.3.3-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:ddedd300cd690a3b06e7eac90ed4452348b1348635777ce23d460d913b5b63c3"},
275 | {file = "setproctitle-1.3.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:415bfcfd01d1fbf5cbd75004599ef167a533395955305f42220a585f64036081"},
276 | {file = "setproctitle-1.3.3-cp39-cp39-win32.whl", hash = "sha256:21112fcd2195d48f25760f0eafa7a76510871bbb3b750219310cf88b04456ae3"},
277 | {file = "setproctitle-1.3.3-cp39-cp39-win_amd64.whl", hash = "sha256:5a740f05d0968a5a17da3d676ce6afefebeeeb5ce137510901bf6306ba8ee002"},
278 | {file = "setproctitle-1.3.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6b9e62ddb3db4b5205c0321dd69a406d8af9ee1693529d144e86bd43bcb4b6c0"},
279 | {file = "setproctitle-1.3.3-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e3b99b338598de0bd6b2643bf8c343cf5ff70db3627af3ca427a5e1a1a90dd9"},
280 | {file = "setproctitle-1.3.3-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ae9a02766dad331deb06855fb7a6ca15daea333b3967e214de12cfae8f0ef5"},
281 | {file = "setproctitle-1.3.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:200ede6fd11233085ba9b764eb055a2a191fb4ffb950c68675ac53c874c22e20"},
282 | {file = "setproctitle-1.3.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0d3a953c50776751e80fe755a380a64cb14d61e8762bd43041ab3f8cc436092f"},
283 | {file = "setproctitle-1.3.3-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5e08e232b78ba3ac6bc0d23ce9e2bee8fad2be391b7e2da834fc9a45129eb87"},
284 | {file = "setproctitle-1.3.3-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f1da82c3e11284da4fcbf54957dafbf0655d2389cd3d54e4eaba636faf6d117a"},
285 | {file = "setproctitle-1.3.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:aeaa71fb9568ebe9b911ddb490c644fbd2006e8c940f21cb9a1e9425bd709574"},
286 | {file = "setproctitle-1.3.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:59335d000c6250c35989394661eb6287187854e94ac79ea22315469ee4f4c244"},
287 | {file = "setproctitle-1.3.3-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c3ba57029c9c50ecaf0c92bb127224cc2ea9fda057b5d99d3f348c9ec2855ad3"},
288 | {file = "setproctitle-1.3.3-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d876d355c53d975c2ef9c4f2487c8f83dad6aeaaee1b6571453cb0ee992f55f6"},
289 | {file = "setproctitle-1.3.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:224602f0939e6fb9d5dd881be1229d485f3257b540f8a900d4271a2c2aa4e5f4"},
290 | {file = "setproctitle-1.3.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d7f27e0268af2d7503386e0e6be87fb9b6657afd96f5726b733837121146750d"},
291 | {file = "setproctitle-1.3.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f5e7266498cd31a4572378c61920af9f6b4676a73c299fce8ba93afd694f8ae7"},
292 | {file = "setproctitle-1.3.3-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33c5609ad51cd99d388e55651b19148ea99727516132fb44680e1f28dd0d1de9"},
293 | {file = "setproctitle-1.3.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:eae8988e78192fd1a3245a6f4f382390b61bce6cfcc93f3809726e4c885fa68d"},
294 | {file = "setproctitle-1.3.3.tar.gz", hash = "sha256:c913e151e7ea01567837ff037a23ca8740192880198b7fbb90b16d181607caae"},
295 | ]
296 |
297 | [package.extras]
298 | test = ["pytest"]
299 |
300 | [[package]]
301 | name = "werkzeug"
302 | version = "3.0.6"
303 | description = "The comprehensive WSGI web application library."
304 | optional = false
305 | python-versions = ">=3.8"
306 | files = [
307 | {file = "werkzeug-3.0.6-py3-none-any.whl", hash = "sha256:1bc0c2310d2fbb07b1dd1105eba2f7af72f322e1e455f2f93c993bee8c8a5f17"},
308 | {file = "werkzeug-3.0.6.tar.gz", hash = "sha256:a8dd59d4de28ca70471a34cba79bed5f7ef2e036a76b3ab0835474246eb41f8d"},
309 | ]
310 |
311 | [package.dependencies]
312 | MarkupSafe = ">=2.1.1"
313 |
314 | [package.extras]
315 | watchdog = ["watchdog (>=2.3)"]
316 |
317 | [metadata]
318 | lock-version = "2.0"
319 | python-versions = "^3.12"
320 | content-hash = "7b2d822fbe1961a64253b48a13cb185caf097f127d4e3993d22cd60e2cb972d8"
321 |
--------------------------------------------------------------------------------
/pyproject.toml:
--------------------------------------------------------------------------------
1 | [tool.poetry]
2 | name = "sdash"
3 | version = "0.3.6"
4 | description = "A simple server dashboard for smaller private servers"
5 | authors = ["Nighty3098 <154594695+Nighty3098@users.noreply.github.com>"]
6 | readme = "README.md"
7 |
8 | [tool.poetry.dependencies]
9 | python = "^3.12"
10 | psutil = "^6.1.0"
11 | flask = "^3.0.3"
12 | pynvml = "^11.5.3"
13 | setproctitle = "^1.3.3"
14 |
15 |
16 | [build-system]
17 | requires = ["poetry-core"]
18 | build-backend = "poetry.core.masonry.api"
19 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | aiohappyeyeballs==2.4.0
2 | aiohttp==3.10.5
3 | aiosignal==1.3.1
4 | asyncio==3.4.3
5 | attrs==24.2.0
6 | blinker==1.8.2
7 | click==8.1.7
8 | disutils==1.4.32.post2
9 | Flask==3.0.3
10 | Flask-SQLAlchemy==3.1.1
11 | frozenlist==1.4.1
12 | GPUtil==1.4.0
13 | greenlet==3.0.3
14 | idna==3.8
15 | itsdangerous==2.2.0
16 | Jinja2==3.1.4
17 | MarkupSafe==2.1.5
18 | multidict==6.0.5
19 | psutil==6.0.0
20 | pynvml==11.5.3
21 | setproctitle==1.3.3
22 | SQLAlchemy==2.0.32
23 | typing_extensions==4.12.2
24 | Werkzeug==3.0.4
25 | yarl==1.9.6
26 |
--------------------------------------------------------------------------------