m5-mikufetch 0.2.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,50 @@
1
+ name: Upload Python Package
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ jobs:
12
+ release-build:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+
17
+ - uses: actions/setup-python@v5
18
+ with:
19
+ python-version: "3.x"
20
+
21
+ - name: Build release distributions
22
+ run: |
23
+ python -m pip install build
24
+ python -m build
25
+
26
+ - name: Upload distributions
27
+ uses: actions/upload-artifact@v4
28
+ with:
29
+ name: release-dists
30
+ path: dist/
31
+
32
+ pypi-publish:
33
+ runs-on: ubuntu-latest
34
+ needs:
35
+ - release-build
36
+ permissions:
37
+ id-token: write
38
+ environment:
39
+ name: pypi
40
+ steps:
41
+ - name: Retrieve release distributions
42
+ uses: actions/download-artifact@v4
43
+ with:
44
+ name: release-dists
45
+ path: dist/
46
+
47
+ - name: Publish release distributions to PyPI
48
+ uses: pypa/gh-action-pypi-publish@release/v1
49
+ with:
50
+ packages-dir: dist/
@@ -0,0 +1,71 @@
1
+ name: Release m5-mikufetch
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: write
11
+ id-token: write
12
+
13
+ jobs:
14
+ build-all:
15
+ runs-on: ubuntu-latest
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - name: Set up Python
20
+ uses: actions/setup-python@v5
21
+ with:
22
+ python-version: '3.11'
23
+
24
+ - name: Build tar.gz + whl
25
+ run: |
26
+ pip install build
27
+ python -m build
28
+
29
+ - name: Install nfpm
30
+ run: |
31
+ echo 'deb [trusted=yes] https://repo.goreleaser.com/apt/ /' | sudo tee /etc/apt/sources.list.d/goreleaser.list
32
+ sudo apt-get update
33
+ sudo apt-get install nfpm
34
+
35
+ - name: Build .deb and .rpm
36
+ run: |
37
+ nfpm pkg --packager deb --target dist/
38
+ nfpm pkg --packager rpm --target dist/
39
+
40
+ - name: Build Windows zip
41
+ run: |
42
+ echo "@echo off" > run_mikufetch.bat
43
+ echo "python mikufetch/main.py %*" >> run_mikufetch.bat
44
+ echo "pause" >> run_mikufetch.bat
45
+ zip -r dist/mikufetch-windows.zip mikufetch/ run_mikufetch.bat pyproject.toml README.md
46
+
47
+ - name: Upload Release
48
+ uses: softprops/action-gh-release@v2
49
+ with:
50
+ tag_name: ${{ github.ref_name }}
51
+ name: "m5-mikufetch ${{ github.ref_name }}"
52
+ body: |
53
+ ## 🎵 m5-mikufetch ${{ github.ref_name }}
54
+
55
+ ### Install
56
+ ```bash
57
+ pip install m5-mikufetch
58
+ ```
59
+
60
+ ### Packages
61
+ | File | Platform |
62
+ |------|----------|
63
+ | `.whl` | pip / PyPI |
64
+ | `.tar.gz` | source |
65
+ | `.deb` | Ubuntu / Debian |
66
+ | `.rpm` | Fedora / RHEL |
67
+ | `.zip` | Windows |
68
+ files: |
69
+ dist/*
70
+ env:
71
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 M5 Dev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,129 @@
1
+ Metadata-Version: 2.4
2
+ Name: m5-mikufetch
3
+ Version: 0.2.0
4
+ Summary: A Hatsune Miku & Kasane Teto themed system fetch tool for the terminal
5
+ Author-email: M5 Dev <claus.valca67@gmail.com>
6
+ License: MIT
7
+ License-File: LICENSE
8
+ Keywords: cli,fetch,miku,neofetch,system-info,teto,utau,vocaloid
9
+ Requires-Python: >=3.11
10
+ Requires-Dist: psutil>=5.9
11
+ Description-Content-Type: text/markdown
12
+
13
+ # mikufetch 🎵
14
+
15
+ A Hatsune Miku & Kasane Teto themed system fetch tool for the terminal, written in Python.
16
+
17
+ If you are looking for a Neofetch alternative that brings your favorite Vocaloid to your terminal, **mikufetch** is the perfect choice for your Linux rice 🌸
18
+
19
+ ```
20
+ || || runner@hostname
21
+ || || ─────────────────
22
+ ( \_____/ ) OS Ubuntu 24.04.2 LTS
23
+ | (^ ^) | Kernel 6.14.11
24
+ | u | CPU AMD EPYC 9B14
25
+ | ~-----~ | RAM 4.20GB / 15.6GB
26
+ | [===] | Shell bash
27
+ \ | | / Terminal xterm-256color
28
+ \ | | / Uptime 2d 4h 30m
29
+ /\ | | /\ Packages 512 (apt)
30
+ / \_|_|_/ \
31
+ / MIKU 39 \
32
+ ```
33
+
34
+ ![Python](https://img.shields.io/badge/python-3.11+-blue.svg)
35
+ ![License](https://img.shields.io/badge/license-MIT-green.svg)
36
+ ![Stars](https://img.shields.io/github/stars/M5Develop/mikufetch?style=social)
37
+ ![PyPI](https://img.shields.io/pypi/v/m5-mikufetch)
38
+
39
+ ---
40
+
41
+ ## Features
42
+
43
+ - **Hatsune Miku** ASCII art rendered in **CYAN** 💙
44
+ - **Kasane Teto** ASCII art rendered in **RED** ❤️
45
+ - **Random mode** — let fate decide your character
46
+ - **OS & Kernel** — reads from `/etc/os-release` and `platform.release()`
47
+ - **CPU** — fast direct read from `/proc/cpuinfo`, falls back to `platform.processor()`
48
+ - **RAM** — used / total via `psutil`
49
+ - **Shell** — bulletproof detection: checks `$SHELL`, then `/proc/self/exe`, then parent PID
50
+ - **Terminal** — reads `$TERM_PROGRAM`, `$COLORTERM`, and `$TERM`
51
+ - **Uptime** — calculated from `psutil.boot_time()`, displayed as `Xd Xh Xm`
52
+ - **Package count** — supports `apt`, `pacman`, `dnf`, and `apk`
53
+
54
+ ---
55
+
56
+ ## Installation
57
+
58
+ ```bash
59
+ pip install m5-mikufetch
60
+ ```
61
+
62
+ Then run from anywhere:
63
+
64
+ ```bash
65
+ mikufetch
66
+ ```
67
+
68
+ ---
69
+
70
+ ## Usage
71
+
72
+ ```bash
73
+ # Default — Hatsune Miku 💙
74
+ mikufetch
75
+
76
+ # Kasane Teto mode 🔴
77
+ mikufetch --teto
78
+ mikufetch -t
79
+
80
+ # Pick manually
81
+ mikufetch --art miku
82
+ mikufetch --art teto
83
+
84
+ # Random character
85
+ mikufetch --random
86
+ mikufetch -r
87
+ ```
88
+
89
+ ---
90
+
91
+ ## Requirements
92
+
93
+ - Python 3.11+
94
+ - `psutil >= 5.9`
95
+ - Linux (macOS/Windows partial support)
96
+
97
+ ---
98
+
99
+ ## Project structure
100
+
101
+ ```
102
+ mikufetch/
103
+ ├── mikufetch/
104
+ │ ├── __init__.py
105
+ │ ├── main.py # System info logic, CLI, and rendering
106
+ │ └── ascii_art.py # Miku & Teto ASCII art
107
+ ├── pyproject.toml
108
+ ├── nfpm.yaml
109
+ └── README.md
110
+ ```
111
+
112
+ ---
113
+
114
+ ## Development
115
+
116
+ ```bash
117
+ git clone https://github.com/M5Develop/mikufetch
118
+ cd mikufetch
119
+ pip install -e .
120
+ mikufetch --teto
121
+ ```
122
+
123
+ ---
124
+
125
+ ## License
126
+
127
+ MIT — made with 💙❤️ by [M5Dev](https://github.com/M5Develop)
128
+
129
+ Miku & Teto ASCII art are fan-made. Not affiliated with Crypton Future Media or TWINDRILL.
@@ -0,0 +1,117 @@
1
+ # mikufetch 🎵
2
+
3
+ A Hatsune Miku & Kasane Teto themed system fetch tool for the terminal, written in Python.
4
+
5
+ If you are looking for a Neofetch alternative that brings your favorite Vocaloid to your terminal, **mikufetch** is the perfect choice for your Linux rice 🌸
6
+
7
+ ```
8
+ || || runner@hostname
9
+ || || ─────────────────
10
+ ( \_____/ ) OS Ubuntu 24.04.2 LTS
11
+ | (^ ^) | Kernel 6.14.11
12
+ | u | CPU AMD EPYC 9B14
13
+ | ~-----~ | RAM 4.20GB / 15.6GB
14
+ | [===] | Shell bash
15
+ \ | | / Terminal xterm-256color
16
+ \ | | / Uptime 2d 4h 30m
17
+ /\ | | /\ Packages 512 (apt)
18
+ / \_|_|_/ \
19
+ / MIKU 39 \
20
+ ```
21
+
22
+ ![Python](https://img.shields.io/badge/python-3.11+-blue.svg)
23
+ ![License](https://img.shields.io/badge/license-MIT-green.svg)
24
+ ![Stars](https://img.shields.io/github/stars/M5Develop/mikufetch?style=social)
25
+ ![PyPI](https://img.shields.io/pypi/v/m5-mikufetch)
26
+
27
+ ---
28
+
29
+ ## Features
30
+
31
+ - **Hatsune Miku** ASCII art rendered in **CYAN** 💙
32
+ - **Kasane Teto** ASCII art rendered in **RED** ❤️
33
+ - **Random mode** — let fate decide your character
34
+ - **OS & Kernel** — reads from `/etc/os-release` and `platform.release()`
35
+ - **CPU** — fast direct read from `/proc/cpuinfo`, falls back to `platform.processor()`
36
+ - **RAM** — used / total via `psutil`
37
+ - **Shell** — bulletproof detection: checks `$SHELL`, then `/proc/self/exe`, then parent PID
38
+ - **Terminal** — reads `$TERM_PROGRAM`, `$COLORTERM`, and `$TERM`
39
+ - **Uptime** — calculated from `psutil.boot_time()`, displayed as `Xd Xh Xm`
40
+ - **Package count** — supports `apt`, `pacman`, `dnf`, and `apk`
41
+
42
+ ---
43
+
44
+ ## Installation
45
+
46
+ ```bash
47
+ pip install m5-mikufetch
48
+ ```
49
+
50
+ Then run from anywhere:
51
+
52
+ ```bash
53
+ mikufetch
54
+ ```
55
+
56
+ ---
57
+
58
+ ## Usage
59
+
60
+ ```bash
61
+ # Default — Hatsune Miku 💙
62
+ mikufetch
63
+
64
+ # Kasane Teto mode 🔴
65
+ mikufetch --teto
66
+ mikufetch -t
67
+
68
+ # Pick manually
69
+ mikufetch --art miku
70
+ mikufetch --art teto
71
+
72
+ # Random character
73
+ mikufetch --random
74
+ mikufetch -r
75
+ ```
76
+
77
+ ---
78
+
79
+ ## Requirements
80
+
81
+ - Python 3.11+
82
+ - `psutil >= 5.9`
83
+ - Linux (macOS/Windows partial support)
84
+
85
+ ---
86
+
87
+ ## Project structure
88
+
89
+ ```
90
+ mikufetch/
91
+ ├── mikufetch/
92
+ │ ├── __init__.py
93
+ │ ├── main.py # System info logic, CLI, and rendering
94
+ │ └── ascii_art.py # Miku & Teto ASCII art
95
+ ├── pyproject.toml
96
+ ├── nfpm.yaml
97
+ └── README.md
98
+ ```
99
+
100
+ ---
101
+
102
+ ## Development
103
+
104
+ ```bash
105
+ git clone https://github.com/M5Develop/mikufetch
106
+ cd mikufetch
107
+ pip install -e .
108
+ mikufetch --teto
109
+ ```
110
+
111
+ ---
112
+
113
+ ## License
114
+
115
+ MIT — made with 💙❤️ by [M5Dev](https://github.com/M5Develop)
116
+
117
+ Miku & Teto ASCII art are fan-made. Not affiliated with Crypton Future Media or TWINDRILL.
@@ -0,0 +1 @@
1
+ __version__ = "0.2.0"
@@ -0,0 +1,42 @@
1
+ CYAN = "\033[96m"
2
+ RED = "\033[91m"
3
+ WHITE = "\033[97m"
4
+ RESET = "\033[0m"
5
+
6
+ MIKU_LINES = [
7
+ r" || || ",
8
+ r" || || ",
9
+ r" ( \_____/ ) ",
10
+ r" | (^ ^) | ",
11
+ r" | u | ",
12
+ r" | ~-----~ | ",
13
+ r" | [===] | ",
14
+ r" \ | | / ",
15
+ r" \ | | / ",
16
+ r" /\ | | /\ ",
17
+ r" / \_|_|_/ \ ",
18
+ r" / MIKU 39 \ ",
19
+ ]
20
+
21
+ TETO_LINES = [
22
+ r" /\ /\ ",
23
+ r" / \_____/ \ ",
24
+ r" | drill hair | ",
25
+ r" \ (>w<) / ",
26
+ r" | ___ | ",
27
+ r" | [===] | ",
28
+ r" | | | | ",
29
+ r" \ | | / ",
30
+ r" /\| | |/\ ",
31
+ r" / \| |/ \ ",
32
+ r" / KASANE TETO \ ",
33
+ r"/ UTAU 100 \ ",
34
+ ]
35
+
36
+ MIKU_ART = [f"{CYAN}{line}{RESET}" for line in MIKU_LINES]
37
+ TETO_ART = [f"{RED}{line}{RESET}" for line in TETO_LINES]
38
+
39
+ ARTS = {
40
+ "miku": MIKU_ART,
41
+ "teto": TETO_ART,
42
+ }
@@ -0,0 +1,194 @@
1
+ import psutil
2
+ import platform
3
+ import os
4
+ import time
5
+ import getpass
6
+ import subprocess
7
+ import argparse
8
+ import random
9
+
10
+ from mikufetch.ascii_art import MIKU_ART, TETO_ART, ARTS, CYAN, RED, WHITE, RESET
11
+
12
+ BOLD = "\033[1m"
13
+ DIM = "\033[2m"
14
+
15
+
16
+ def get_distro() -> str:
17
+ if platform.system() == "Linux":
18
+ try:
19
+ with open("/etc/os-release") as f:
20
+ for line in f:
21
+ if line.startswith("PRETTY_NAME"):
22
+ return line.split("=", 1)[1].strip().strip('"')
23
+ except Exception:
24
+ pass
25
+ return platform.system()
26
+
27
+
28
+ def get_cpu_info() -> str:
29
+ if platform.system() == "Linux":
30
+ try:
31
+ with open("/proc/cpuinfo") as f:
32
+ for line in f:
33
+ if line.startswith("model name"):
34
+ return line.split(":", 1)[1].strip()
35
+ except Exception:
36
+ pass
37
+ return platform.processor() or "Unknown CPU"
38
+
39
+
40
+ def get_shell() -> str:
41
+ shell_env = os.environ.get("SHELL", "")
42
+ if shell_env:
43
+ name = shell_env.split("/")[-1]
44
+ if name not in ("sh", ""):
45
+ return name
46
+ skip = {"sh", "python", "python3", "python3.11", "python3.12", ""}
47
+ pid = os.getppid()
48
+ for _ in range(5):
49
+ try:
50
+ resolved = os.readlink(f"/proc/{pid}/exe")
51
+ name = resolved.split("/")[-1]
52
+ if name not in skip:
53
+ return name
54
+ with open(f"/proc/{pid}/status") as f:
55
+ for line in f:
56
+ if line.startswith("PPid:"):
57
+ pid = int(line.split()[1])
58
+ break
59
+ except Exception:
60
+ break
61
+ return shell_env.split("/")[-1] if shell_env else "sh"
62
+
63
+
64
+ def get_terminal() -> str:
65
+ for var in ("TERM_PROGRAM", "TERMINAL", "COLORTERM", "TERM"):
66
+ val = os.environ.get(var, "")
67
+ if val:
68
+ return val
69
+ return "unknown"
70
+
71
+
72
+ def get_uptime() -> str:
73
+ seconds = int(time.time() - psutil.boot_time())
74
+ days, remainder = divmod(seconds, 86400)
75
+ hours, remainder = divmod(remainder, 3600)
76
+ minutes, _ = divmod(remainder, 60)
77
+ parts = []
78
+ if days:
79
+ parts.append(f"{days}d")
80
+ if hours:
81
+ parts.append(f"{hours}h")
82
+ parts.append(f"{minutes}m")
83
+ return " ".join(parts)
84
+
85
+
86
+ def get_packages() -> str:
87
+ managers = {
88
+ "apt": ["dpkg-query", "-f", "${binary:Package}\n", "-W"],
89
+ "pacman": ["pacman", "-Qq"],
90
+ "dnf": ["rpm", "-qa"],
91
+ "apk": ["apk", "info"],
92
+ }
93
+ for mgr, cmd in managers.items():
94
+ try:
95
+ result = subprocess.run(
96
+ cmd,
97
+ stdout=subprocess.PIPE,
98
+ stderr=subprocess.DEVNULL,
99
+ timeout=3,
100
+ )
101
+ count = len(result.stdout.decode(errors="ignore").strip().splitlines())
102
+ if count > 0:
103
+ return f"{count} ({mgr})"
104
+ except Exception:
105
+ continue
106
+ return "N/A"
107
+
108
+
109
+ def get_sys_info() -> dict:
110
+ return {
111
+ "user": getpass.getuser(),
112
+ "host": platform.node(),
113
+ "os": get_distro(),
114
+ "kernel": platform.release().split("-")[0],
115
+ "cpu": get_cpu_info(),
116
+ "ram": (
117
+ f"{round(psutil.virtual_memory().used / 1024**3, 2)}GB"
118
+ f" / "
119
+ f"{round(psutil.virtual_memory().total / 1024**3, 2)}GB"
120
+ ),
121
+ "shell": get_shell(),
122
+ "terminal": get_terminal(),
123
+ "uptime": get_uptime(),
124
+ "packages": get_packages(),
125
+ }
126
+
127
+
128
+ def build_info_lines(info: dict, color: str) -> list[str]:
129
+ label = lambda k: f"{color}{BOLD}{k}{RESET}{WHITE}"
130
+ sep = f"{DIM}@{RESET}"
131
+ return [
132
+ f"{BOLD}{info['user']}{sep}{info['host']}{RESET}",
133
+ f"{DIM}{'─' * (len(info['user']) + len(info['host']) + 1)}{RESET}",
134
+ f"{label('OS')} {info['os']}",
135
+ f"{label('Kernel')} {info['kernel']}",
136
+ f"{label('CPU')} {info['cpu']}",
137
+ f"{label('RAM')} {info['ram']}",
138
+ f"{label('Shell')} {info['shell']}",
139
+ f"{label('Terminal')} {info['terminal']}",
140
+ f"{label('Uptime')} {info['uptime']}",
141
+ f"{label('Packages')} {info['packages']}",
142
+ ]
143
+
144
+
145
+ def main():
146
+ parser = argparse.ArgumentParser(
147
+ prog="mikufetch",
148
+ description="🎵 System fetch tool — Miku & Teto edition"
149
+ )
150
+ parser.add_argument(
151
+ "--art", "-a",
152
+ choices=["miku", "teto"],
153
+ default=None,
154
+ help="Choose character: miku (default) or teto"
155
+ )
156
+ parser.add_argument(
157
+ "--teto", "-t",
158
+ action="store_true",
159
+ help="Kasane Teto mode 🔴"
160
+ )
161
+ parser.add_argument(
162
+ "--random", "-r",
163
+ action="store_true",
164
+ help="Random character"
165
+ )
166
+ args = parser.parse_args()
167
+
168
+ if args.random:
169
+ choice = random.choice(["miku", "teto"])
170
+ elif args.teto:
171
+ choice = "teto"
172
+ elif args.art:
173
+ choice = args.art
174
+ else:
175
+ choice = "miku"
176
+
177
+ art = ARTS[choice]
178
+ color = RED if choice == "teto" else CYAN
179
+
180
+ info = get_sys_info()
181
+ info_lines = build_info_lines(info, color)
182
+
183
+ rows = max(len(art), len(info_lines))
184
+ art_lines = art + [" "] * (rows - len(art))
185
+ info_lines = info_lines + [""] * (rows - len(info_lines))
186
+
187
+ print()
188
+ for art_line, info_line in zip(art_lines, info_lines):
189
+ print(f"{art_line} {info_line}{RESET}")
190
+ print()
191
+
192
+
193
+ if __name__ == "__main__":
194
+ main()
@@ -0,0 +1,18 @@
1
+ name: "m5-mikufetch"
2
+ arch: "amd64"
3
+ platform: "linux"
4
+ version: "0.2.0"
5
+ section: "utils"
6
+ priority: "optional"
7
+ maintainer: "Claus <claus.valca67@gmail.com>"
8
+ description: "A stylish system fetch tool featuring Hatsune Miku & Kasane Teto."
9
+ vendor: "M5Develop"
10
+ homepage: "https://github.com/M5Develop/mikufetch"
11
+ license: "MIT"
12
+
13
+ contents:
14
+ - src: "mikufetch/main.py"
15
+ dst: "/usr/bin/m5-mikufetch"
16
+ type: "file"
17
+ file_info:
18
+ mode: 0755
@@ -0,0 +1,22 @@
1
+ [project]
2
+ name = "m5-mikufetch"
3
+ version = "0.2.0"
4
+ description = "A Hatsune Miku & Kasane Teto themed system fetch tool for the terminal"
5
+ authors = [{ name = "M5 Dev", email = "claus.valca67@gmail.com" }]
6
+ readme = "README.md"
7
+ requires-python = ">=3.11"
8
+ license = { text = "MIT" }
9
+ keywords = ["fetch", "neofetch", "miku", "teto", "vocaloid", "utau", "system-info", "cli"]
10
+ dependencies = [
11
+ "psutil>=5.9",
12
+ ]
13
+
14
+ [project.scripts]
15
+ mikufetch = "mikufetch.main:main"
16
+
17
+ [build-system]
18
+ requires = ["hatchling"]
19
+ build-backend = "hatchling.build"
20
+
21
+ [tool.hatch.build.targets.wheel]
22
+ packages = ["mikufetch"]