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.
- m5_mikufetch-0.2.0/.github/workflows/python-publish.yml +50 -0
- m5_mikufetch-0.2.0/.github/workflows/release.yml +71 -0
- m5_mikufetch-0.2.0/LICENSE +21 -0
- m5_mikufetch-0.2.0/PKG-INFO +129 -0
- m5_mikufetch-0.2.0/README.md +117 -0
- m5_mikufetch-0.2.0/mikufetch/__init__.py +1 -0
- m5_mikufetch-0.2.0/mikufetch/ascii_art.py +42 -0
- m5_mikufetch-0.2.0/mikufetch/main.py +194 -0
- m5_mikufetch-0.2.0/nfpm.yaml +18 -0
- m5_mikufetch-0.2.0/pyproject.toml +22 -0
|
@@ -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
|
+

|
|
35
|
+

|
|
36
|
+

|
|
37
|
+

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

|
|
23
|
+

|
|
24
|
+

|
|
25
|
+

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