nexfetch 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,41 @@
1
+ Metadata-Version: 2.4
2
+ Name: nexfetch
3
+ Version: 1.0.0
4
+ Summary: Neofetch-like system info tool by Nexa
5
+ License: MIT
6
+ Keywords: neofetch,sysinfo,terminal,android,termux
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Operating System :: POSIX :: Linux
10
+ Classifier: Environment :: Console
11
+ Requires-Python: >=3.8
12
+ Description-Content-Type: text/markdown
13
+
14
+ # nexfetch
15
+
16
+ Neofetch-like system info tool, support Android/Termux/Linux.
17
+
18
+ ## Install
19
+
20
+ ```bash
21
+ pip install nexfetch
22
+ ```
23
+
24
+ ## Usage
25
+
26
+ ```bash
27
+ nexfetch
28
+ ```
29
+
30
+ ## Custom Logo
31
+
32
+ Tambah logo distro sendiri di `~/.config/nexfetch/logos/<distro>.txt`:
33
+
34
+ ```
35
+ COLOR=cyan
36
+ /\
37
+ / \
38
+ /____\
39
+ ```
40
+
41
+ by Nexa
@@ -0,0 +1,28 @@
1
+ # nexfetch
2
+
3
+ Neofetch-like system info tool, support Android/Termux/Linux.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pip install nexfetch
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```bash
14
+ nexfetch
15
+ ```
16
+
17
+ ## Custom Logo
18
+
19
+ Tambah logo distro sendiri di `~/.config/nexfetch/logos/<distro>.txt`:
20
+
21
+ ```
22
+ COLOR=cyan
23
+ /\
24
+ / \
25
+ /____\
26
+ ```
27
+
28
+ by Nexa
@@ -0,0 +1 @@
1
+ from .core import main
@@ -0,0 +1,7 @@
1
+ COLOR=blue
2
+ /\
3
+ / \
4
+ / /\ \
5
+ / / \ \
6
+ /_/ /\ \_\
7
+ \_\/ \/_/
@@ -0,0 +1,12 @@
1
+ COLOR=green
2
+ .-------.
3
+ / * * \
4
+ |___________|
5
+ .-| |-.
6
+ | | | |
7
+ | | ANDROID | |
8
+ | |___________| |
9
+ '-| |-'
10
+ |___________|
11
+ | | | |
12
+ '--' '--'
@@ -0,0 +1,7 @@
1
+ COLOR=cyan
2
+ /\
3
+ / \
4
+ /\ \
5
+ / __ \
6
+ / / \ \
7
+ /_/ \_\
@@ -0,0 +1,363 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ nexfetch v1.0 - System info display by Nexa
4
+ Logo dibaca dari file: /etc/nexfetch/logos/<distro>.txt
5
+ atau fallback ke : ~/.config/nexfetch/logos/<distro>.txt
6
+ """
7
+
8
+ import platform
9
+ import os
10
+ import subprocess
11
+ import sys
12
+
13
+ VERSION = "1.0"
14
+
15
+ # ─── ANSI COLORS ─────────────────────────────────────────────────────────────
16
+ R = "\033[0m"
17
+ B = "\033[1m"
18
+ CY = "\033[96m"
19
+ GR = "\033[92m"
20
+ YL = "\033[93m"
21
+ BL = "\033[94m"
22
+ MG = "\033[95m"
23
+ RD = "\033[91m"
24
+ WH = "\033[97m"
25
+
26
+ COLOR_MAP = {
27
+ "cyan": CY,
28
+ "green": GR,
29
+ "yellow": YL,
30
+ "blue": BL,
31
+ "magenta": MG,
32
+ "red": RD,
33
+ "white": WH,
34
+ }
35
+
36
+ # ─── LOGO DIRS (priority order) ───────────────────────────────────────────────
37
+ LOGO_DIRS = [
38
+ os.path.expanduser("~/.config/nexfetch/logos"), # user custom
39
+ "/etc/nexfetch/logos", # system-wide
40
+ os.path.join(os.path.dirname(os.path.abspath(__file__))), # bundled di dalam package (pip install)
41
+ os.path.join(os.path.dirname(os.path.abspath(__file__)), "logos"), # next to script
42
+ ]
43
+
44
+ # ─── DISTRO → FILENAME MAPPING ────────────────────────────────────────────────
45
+ DISTRO_MAP = {
46
+ "arch": "arch",
47
+ "ubuntu": "ubuntu",
48
+ "debian": "debian",
49
+ "kali": "kali",
50
+ "manjaro": "manjaro",
51
+ "fedora": "fedora",
52
+ "termux": "termux",
53
+ "android": "android",
54
+ "alpine": "alpine",
55
+ "void": "void",
56
+ "opensuse": "opensuse",
57
+ "centos": "centos",
58
+ "mint": "mint",
59
+ "pop": "pop",
60
+ "endeavour": "arch", # EndeavourOS pakai logo Arch
61
+ "garuda": "arch",
62
+ }
63
+
64
+ # ─── LOGO LOADER ──────────────────────────────────────────────────────────────
65
+ def load_logo(name):
66
+ """
67
+ Load logo dari file .txt
68
+ Format file:
69
+ Baris pertama: COLOR=<colorname> (opsional)
70
+ Sisa baris : ASCII art
71
+ Return: (ansi_color_str, [lines])
72
+ """
73
+ filename = f"{name}.txt"
74
+ for logo_dir in LOGO_DIRS:
75
+ path = os.path.join(logo_dir, filename)
76
+ if os.path.isfile(path):
77
+ with open(path, "r", encoding="utf-8") as f:
78
+ lines = f.read().splitlines()
79
+
80
+ color = WH # default
81
+ art_lines = []
82
+ for i, line in enumerate(lines):
83
+ if i == 0 and line.upper().startswith("COLOR="):
84
+ color_name = line.split("=", 1)[1].strip().lower()
85
+ color = COLOR_MAP.get(color_name, WH)
86
+ else:
87
+ art_lines.append(line)
88
+
89
+ # Trim trailing empty lines
90
+ while art_lines and not art_lines[-1].strip():
91
+ art_lines.pop()
92
+
93
+ return color, art_lines
94
+
95
+ return None, None # tidak ditemukan
96
+
97
+ def get_logo(distro_key):
98
+ """Coba load logo distro, fallback ke 'linux', lalu 'unknown'"""
99
+ color, lines = load_logo(distro_key)
100
+ if lines:
101
+ return color, lines
102
+
103
+ color, lines = load_logo("linux")
104
+ if lines:
105
+ return color, lines
106
+
107
+ color, lines = load_logo("unknown")
108
+ if lines:
109
+ return color, lines
110
+
111
+ # Hardcoded last resort kalau file unknown.txt juga ga ada
112
+ return WH, [
113
+ " .--------. ",
114
+ " | NEXFETCH| ",
115
+ " |--------| ",
116
+ " | LINUX | ",
117
+ " '--------' ",
118
+ ]
119
+
120
+ # ─── HELPERS ──────────────────────────────────────────────────────────────────
121
+ def run_cmd(cmd):
122
+ try:
123
+ out = subprocess.check_output(cmd, shell=True, stderr=subprocess.DEVNULL).decode().strip()
124
+ return out if out else None
125
+ except:
126
+ return None
127
+
128
+ def is_android():
129
+ return (
130
+ os.path.exists("/system/build.prop") or
131
+ run_cmd("getprop ro.build.version.release") is not None
132
+ )
133
+
134
+ # ─── INFO GETTERS ──────────────────────────────────────────────────────────────
135
+ def get_distro_key():
136
+ if is_android():
137
+ try:
138
+ with open("/etc/os-release") as f:
139
+ content = f.read().lower()
140
+ for key in DISTRO_MAP:
141
+ if key in content:
142
+ return key
143
+ except:
144
+ pass
145
+ return "android"
146
+ try:
147
+ with open("/etc/os-release") as f:
148
+ content = f.read().lower()
149
+ for key in DISTRO_MAP:
150
+ if key in content:
151
+ return DISTRO_MAP[key]
152
+ except:
153
+ pass
154
+ return "linux"
155
+
156
+ def get_device():
157
+ brand = run_cmd("getprop ro.product.brand")
158
+ model = run_cmd("getprop ro.product.model")
159
+ if brand and model:
160
+ return f"{brand.capitalize()} {model}"
161
+ for path in ["/sys/devices/virtual/dmi/id/product_name",
162
+ "/sys/firmware/devicetree/base/model"]:
163
+ try:
164
+ with open(path) as f:
165
+ v = f.read().strip().replace('\x00', '')
166
+ if v:
167
+ return v
168
+ except:
169
+ pass
170
+ return platform.node()
171
+
172
+ def get_os_name():
173
+ android_ver = run_cmd("getprop ro.build.version.release")
174
+ if android_ver:
175
+ return f"Android {android_ver}"
176
+ try:
177
+ with open("/etc/os-release") as f:
178
+ for line in f:
179
+ if line.startswith("PRETTY_NAME="):
180
+ return line.split("=", 1)[1].strip().strip('"')
181
+ except:
182
+ pass
183
+ return platform.system()
184
+
185
+ def get_kernel():
186
+ return f"Linux {platform.release()}"
187
+
188
+ def get_cpu():
189
+ try:
190
+ with open("/proc/cpuinfo") as f:
191
+ for line in f:
192
+ if "model name" in line:
193
+ return line.split(":")[1].strip()
194
+ if "Hardware" in line:
195
+ hw = line.split(":")[1].strip()
196
+ if 'hw' in dir():
197
+ return hw
198
+ except:
199
+ pass
200
+ return run_cmd("sysctl -n machdep.cpu.brand_string") or platform.processor() or "Unknown"
201
+
202
+ def get_ram():
203
+ try:
204
+ total = avail = 0
205
+ with open("/proc/meminfo") as f:
206
+ for line in f:
207
+ if line.startswith("MemTotal:"):
208
+ total = int(line.split()[1]) // 1024
209
+ elif line.startswith("MemAvailable:"):
210
+ avail = int(line.split()[1]) // 1024
211
+ if total:
212
+ return f"{total - avail} / {total} MB"
213
+ except:
214
+ pass
215
+ return "Unknown"
216
+
217
+ def get_storage():
218
+ try:
219
+ import shutil as sh
220
+ total, used, _ = sh.disk_usage("/")
221
+ return f"{used//(1024**3)} / {total//(1024**3)} GB"
222
+ except:
223
+ return "Unknown"
224
+
225
+ def get_battery():
226
+ for cap_p, stat_p in [
227
+ ("/sys/class/power_supply/battery/capacity",
228
+ "/sys/class/power_supply/battery/status"),
229
+ ("/sys/class/power_supply/BAT0/capacity",
230
+ "/sys/class/power_supply/BAT0/status"),
231
+ ]:
232
+ try:
233
+ with open(cap_p) as f:
234
+ cap = int(f.read().strip())
235
+ status = ""
236
+ try:
237
+ with open(stat_p) as f:
238
+ status = f.read().strip()
239
+ except:
240
+ pass
241
+ icon = " ⚡" if "Charging" in status else ""
242
+ return f"{cap}%{icon}"
243
+ except:
244
+ pass
245
+ return "Unknown"
246
+
247
+ def get_wifi():
248
+ try:
249
+ with open("/proc/net/wireless") as f:
250
+ if len(f.readlines()) > 2:
251
+ return "Connected"
252
+ except:
253
+ pass
254
+ r = run_cmd("ip route 2>/dev/null | grep -c default")
255
+ return "Connected" if r and int(r) > 0 else "Disconnected"
256
+
257
+ def get_ip():
258
+ return (run_cmd("hostname -I 2>/dev/null | awk '{print $1}'") or
259
+ run_cmd("ip route get 1 2>/dev/null | awk '{print $7}' | head -1") or
260
+ "Unknown")
261
+
262
+ def get_python_ver():
263
+ v = sys.version_info
264
+ return f"{v.major}.{v.minor}.{v.micro}"
265
+
266
+ def get_pkg_count():
267
+ for cmd, mgr in [
268
+ ("dpkg -l 2>/dev/null | tail -n +6 | wc -l", "dpkg"),
269
+ ("pacman -Q 2>/dev/null | wc -l", "pacman"),
270
+ ("rpm -qa 2>/dev/null | wc -l", "rpm"),
271
+ ("pkg list-installed 2>/dev/null | grep -v Listing | wc -l", "pkg"),
272
+ ]:
273
+ count = run_cmd(cmd)
274
+ if count and count.isdigit() and int(count) > 0:
275
+ return f"{count} ({mgr})"
276
+ return "Unknown"
277
+
278
+ def get_shell():
279
+ s = os.environ.get("SHELL", "")
280
+ return s.split("/")[-1] if s else "Unknown"
281
+
282
+ def get_uptime():
283
+ try:
284
+ with open("/proc/uptime") as f:
285
+ secs = float(f.read().split()[0])
286
+ return f"{int(secs//3600)}h {int((secs%3600)//60)}m"
287
+ except:
288
+ return "Unknown"
289
+
290
+ # ─── COLOR BARS ───────────────────────────────────────────────────────────────
291
+ def color_bar():
292
+ return "".join("\033[4%dm \033[0m" % i for i in range(8))
293
+
294
+ def bright_bar():
295
+ return "".join("\033[10%dm \033[0m" % i for i in range(8))
296
+
297
+ # ─── BUILD INFO ───────────────────────────────────────────────────────────────
298
+ def build_info(data):
299
+ W = 34
300
+ sep = f"{CY}{'─' * W}{R}"
301
+ def row(key, val):
302
+ return f"{CY}{B}{key:<11}{R}: {WH}{val}{R}"
303
+
304
+ cpu = data['cpu']
305
+ if len(cpu) > 35:
306
+ cpu = cpu[:33] + ".."
307
+
308
+ return [
309
+ f"{CY}{B}NexFetch v{VERSION}{R}",
310
+ sep,
311
+ row("Device", data['device']),
312
+ row("OS", data['os']),
313
+ row("Kernel", data['kernel']),
314
+ row("CPU", cpu),
315
+ row("Memory", data['ram']),
316
+ row("Storage", data['storage']),
317
+ row("Battery", data['battery']),
318
+ row("WiFi", data['wifi']),
319
+ row("IP", data['ip']),
320
+ row("Python", data['python']),
321
+ row("Shell", data['shell']),
322
+ row("Uptime", data['uptime']),
323
+ row("Packages", data['pkgs']),
324
+ sep,
325
+ color_bar(),
326
+ bright_bar(),
327
+ ]
328
+
329
+ # ─── MAIN ─────────────────────────────────────────────────────────────────────
330
+ def main():
331
+ distro_key = get_distro_key()
332
+ logo_color, logo_lines = get_logo(distro_key)
333
+
334
+ data = {
335
+ 'device': get_device(),
336
+ 'os': get_os_name(),
337
+ 'kernel': get_kernel(),
338
+ 'cpu': get_cpu(),
339
+ 'ram': get_ram(),
340
+ 'storage': get_storage(),
341
+ 'battery': get_battery(),
342
+ 'wifi': get_wifi(),
343
+ 'ip': get_ip(),
344
+ 'python': get_python_ver(),
345
+ 'shell': get_shell(),
346
+ 'uptime': get_uptime(),
347
+ 'pkgs': get_pkg_count(),
348
+ }
349
+
350
+ info_lines = build_info(data)
351
+ max_logo = max(len(l) for l in logo_lines) if logo_lines else 0
352
+ max_count = max(len(logo_lines), len(info_lines))
353
+
354
+ logo_lines = logo_lines + [""] * (max_count - len(logo_lines))
355
+ info_lines = info_lines + [""] * (max_count - len(info_lines))
356
+
357
+ print()
358
+ for logo_line, info_line in zip(logo_lines, info_lines):
359
+ print(f" {logo_color}{B}{logo_line.ljust(max_logo)}{R} {info_line}")
360
+ print()
361
+
362
+ if __name__ == "__main__":
363
+ main()
@@ -0,0 +1,10 @@
1
+ COLOR=red
2
+ _____
3
+ / __ \
4
+ | / |
5
+ | \___-
6
+ -_
7
+ --_
8
+ ---
9
+ --_
10
+ -
@@ -0,0 +1,9 @@
1
+ COLOR=blue
2
+ _____
3
+ / __\
4
+ | /
5
+ ___| |___
6
+ / _______ \
7
+ / | | \
8
+ | | | |
9
+ \__|_____|__/
@@ -0,0 +1,10 @@
1
+ COLOR=blue
2
+ .-----.
3
+ / .---. \
4
+ | / ___ \ |
5
+ | || K || |
6
+ | || A || |
7
+ | || L || |
8
+ | || I || |
9
+ \ '---' /
10
+ '-----'
@@ -0,0 +1,8 @@
1
+ COLOR=yellow
2
+ .--.
3
+ |o_o |
4
+ |:_/ |
5
+ // \ \
6
+ (| | )
7
+ /'\_ _/`\
8
+ \___)=(___/
@@ -0,0 +1,6 @@
1
+ COLOR=green
2
+ ██████ ██ ██
3
+ ██ ██ ██
4
+ ██████ ██ ██
5
+ ██ ██ ██
6
+ ██████ ██████
@@ -0,0 +1,6 @@
1
+ COLOR=green
2
+ _____ _____ ____ __ __ _ ___ __
3
+ |_ _| ____| _ \| \/ | | | \ \/ /
4
+ | | | _| | |_) | |\/| | | | |\ /
5
+ | | | |___| _ <| | | | |_| |/ \
6
+ |_| |_____|_| \_\_| |_|\___//_/\_\
@@ -0,0 +1,18 @@
1
+ COLOR=yellow
2
+ .-/+oossssoo+/-.
3
+ `:+ssssssssssssssss+:`
4
+ -+ssssssssssssssssssys-
5
+ .ossssssssssssssssssssso.
6
+ /ssssssssssshdmmNNmmyssss\
7
+ +ssssssssshmydMMMMMMNssss+
8
+ /sssssssshNMMMyhhyyyyhMMs\
9
+ .ssssssssdMMMNhssssssNMMd.
10
+ +sssshhhyNMMNyssssssyNMMy+
11
+ ossyNMMMNyMMhssssssshmmho
12
+ +sssshhhyNMMNyssssssyNMMy+
13
+ .ssssssssdMMMNhssssssNMMd.
14
+ /sssssssshNMMMyhhyyyyhNMs\
15
+ +ssssssssshmydMMMMMMNssss+
16
+ -+ssssssssssssssssssys-
17
+ `:+ssssssssssssssss+:`
18
+ .-/+oossssoo+/-.
@@ -0,0 +1,6 @@
1
+ COLOR=white
2
+ .--------.
3
+ | NEXFETCH|
4
+ |--------|
5
+ | LINUX |
6
+ '--------'
@@ -0,0 +1,41 @@
1
+ Metadata-Version: 2.4
2
+ Name: nexfetch
3
+ Version: 1.0.0
4
+ Summary: Neofetch-like system info tool by Nexa
5
+ License: MIT
6
+ Keywords: neofetch,sysinfo,terminal,android,termux
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Operating System :: POSIX :: Linux
10
+ Classifier: Environment :: Console
11
+ Requires-Python: >=3.8
12
+ Description-Content-Type: text/markdown
13
+
14
+ # nexfetch
15
+
16
+ Neofetch-like system info tool, support Android/Termux/Linux.
17
+
18
+ ## Install
19
+
20
+ ```bash
21
+ pip install nexfetch
22
+ ```
23
+
24
+ ## Usage
25
+
26
+ ```bash
27
+ nexfetch
28
+ ```
29
+
30
+ ## Custom Logo
31
+
32
+ Tambah logo distro sendiri di `~/.config/nexfetch/logos/<distro>.txt`:
33
+
34
+ ```
35
+ COLOR=cyan
36
+ /\
37
+ / \
38
+ /____\
39
+ ```
40
+
41
+ by Nexa
@@ -0,0 +1,20 @@
1
+ README.md
2
+ pyproject.toml
3
+ nexfetch/__init__.py
4
+ nexfetch/alpine.txt
5
+ nexfetch/android.txt
6
+ nexfetch/arch.txt
7
+ nexfetch/core.py
8
+ nexfetch/debian.txt
9
+ nexfetch/fedora.txt
10
+ nexfetch/kali.txt
11
+ nexfetch/linux.txt
12
+ nexfetch/manjaro.txt
13
+ nexfetch/termux.txt
14
+ nexfetch/ubuntu.txt
15
+ nexfetch/unknown.txt
16
+ nexfetch.egg-info/PKG-INFO
17
+ nexfetch.egg-info/SOURCES.txt
18
+ nexfetch.egg-info/dependency_links.txt
19
+ nexfetch.egg-info/entry_points.txt
20
+ nexfetch.egg-info/top_level.txt
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ nexfetch = nexfetch.core:main
@@ -0,0 +1,2 @@
1
+ dist
2
+ nexfetch
@@ -0,0 +1,27 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "nexfetch"
7
+ version = "1.0.0"
8
+ description = "Neofetch-like system info tool by Nexa"
9
+ readme = "README.md"
10
+ license = { text = "MIT" }
11
+ requires-python = ">=3.8"
12
+ keywords = ["neofetch", "sysinfo", "terminal", "android", "termux"]
13
+ classifiers = [
14
+ "Programming Language :: Python :: 3",
15
+ "License :: OSI Approved :: MIT License",
16
+ "Operating System :: POSIX :: Linux",
17
+ "Environment :: Console",
18
+ ]
19
+
20
+ [project.scripts]
21
+ nexfetch = "nexfetch.core:main"
22
+
23
+ [tool.setuptools.packages.find]
24
+ where = ["."]
25
+
26
+ [tool.setuptools.package-data]
27
+ nexfetch = ["*.txt"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+