├── .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 |

404

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