├── .gitattributes ├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── distro-de-wm-shell-hw-request.md │ └── install-issue.md ├── .gitignore ├── Examples ├── appleterm.png ├── gnometerm.png ├── hp.png ├── intelcpu.png ├── konsole.png ├── len.png ├── mac.png ├── pent.png ├── ryzencpu.png ├── tuf.png ├── ubuntu.png └── windows.png ├── LICENSE ├── MANIFEST.in ├── README.md ├── discord.sh ├── fetch_cord.conf ├── fetch_cord ├── Cycle.py ├── Logger.py ├── __init__.py ├── __main__.py ├── args.py ├── computer │ ├── Computer.py │ ├── Peripheral_interface.py │ ├── __init__.py │ ├── cpu │ │ ├── Cpu_amd.py │ │ ├── Cpu_intel.py │ │ ├── Cpu_interface.py │ │ ├── __init__.py │ │ └── get_cpu.py │ ├── flatpak.py │ ├── gpu │ │ ├── Gpu_amd.py │ │ ├── Gpu_intel.py │ │ ├── Gpu_interface.py │ │ ├── Gpu_nvidia.py │ │ ├── __init__.py │ │ └── get_gpu.py │ ├── mobo │ │ ├── __init__.py │ │ └── get_mobo.py │ └── resources.py ├── config.py ├── config_schema.json ├── cycles.py ├── debugger.py ├── resources │ ├── __init__.py │ ├── default.conf │ ├── fetch_cord.conf │ ├── fetchcord_ids.json │ └── systemd_service.py ├── run_command.py ├── run_rpc.py └── update.py ├── setup.py ├── snapcraft.yaml ├── systemd └── fetchcord.service └── tests └── test_fetch_cord_computer.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | # Debug info 11 | 12 | **Please run `fetchcord --debug` and send it here.** 13 | 14 | **If you are unable to run FetchCord please run `neofetch --noart`(windows) or `neofetch -- stdout`(macos&linux)** 15 | 16 | # Operating system & way of installation 17 | 18 | **Please provide your operating system, and how you got FetchCord(AUR, github,pip) here** 19 | 20 | # Error/issue 21 | 22 | **Your error or bug report goes in here.** 23 | 24 | # Other notes(optional) 25 | 26 | **Other notes about the error/issue** 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/distro-de-wm-shell-hw-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Distro/de/wm/shell/hw request 3 | about: request to add a /de/wm/shell/hw 4 | title: '' 5 | labels: distro/wm/hardware/term request 6 | assignees: '' 7 | 8 | --- 9 | 10 | # Debug info 11 | 12 | **Please run `fetchcord --debug` and put it here. You might also want to send the output of `neofetch --noart`(windows) or `neofetch -- stdout`(macos&linux)** 13 | 14 | # Requested item 15 | 16 | **Here goes your desired os/de/wm/shell/hardware request** 17 | 18 | # Other notes 19 | 20 | **Other notes about the request go here** 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/install-issue.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Install issue 3 | about: Get help with installation issues 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | # How you tried to install fetchcord 11 | 12 | **This can be AUR, Github, or pip.** 13 | 14 | # Operating system 15 | 16 | **Your OS goes here.** 17 | 18 | # Other notes 19 | 20 | **Other notes about install error/issue.** 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # celery beat schedule file 95 | celerybeat-schedule 96 | 97 | # SageMath parsed files 98 | *.sage.py 99 | 100 | # Environments 101 | .env 102 | .venv 103 | env/ 104 | venv/ 105 | ENV/ 106 | env.bak/ 107 | venv.bak/ 108 | 109 | # Spyder project settings 110 | .spyderproject 111 | .spyproject 112 | 113 | # Rope project settings 114 | .ropeproject 115 | 116 | # mkdocs documentation 117 | /site 118 | 119 | # mypy 120 | .mypy_cache/ 121 | .dmypy.json 122 | dmypy.json 123 | 124 | # Pyre type checker 125 | .pyre/ 126 | #pycharm file 127 | .idea 128 | 129 | # vim file 130 | .vim/ 131 | 132 | # auth key 133 | authkey_pypi 134 | .DS_Store 135 | 136 | fctest.py 137 | .vscode 138 | samples 139 | 140 | # Snap 141 | *.snap -------------------------------------------------------------------------------- /Examples/appleterm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchcord/FetchCord/3833c0f1464fb5703e712db4ebf0e7f88f22a829/Examples/appleterm.png -------------------------------------------------------------------------------- /Examples/gnometerm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchcord/FetchCord/3833c0f1464fb5703e712db4ebf0e7f88f22a829/Examples/gnometerm.png -------------------------------------------------------------------------------- /Examples/hp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchcord/FetchCord/3833c0f1464fb5703e712db4ebf0e7f88f22a829/Examples/hp.png -------------------------------------------------------------------------------- /Examples/intelcpu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchcord/FetchCord/3833c0f1464fb5703e712db4ebf0e7f88f22a829/Examples/intelcpu.png -------------------------------------------------------------------------------- /Examples/konsole.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchcord/FetchCord/3833c0f1464fb5703e712db4ebf0e7f88f22a829/Examples/konsole.png -------------------------------------------------------------------------------- /Examples/len.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchcord/FetchCord/3833c0f1464fb5703e712db4ebf0e7f88f22a829/Examples/len.png -------------------------------------------------------------------------------- /Examples/mac.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchcord/FetchCord/3833c0f1464fb5703e712db4ebf0e7f88f22a829/Examples/mac.png -------------------------------------------------------------------------------- /Examples/pent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchcord/FetchCord/3833c0f1464fb5703e712db4ebf0e7f88f22a829/Examples/pent.png -------------------------------------------------------------------------------- /Examples/ryzencpu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchcord/FetchCord/3833c0f1464fb5703e712db4ebf0e7f88f22a829/Examples/ryzencpu.png -------------------------------------------------------------------------------- /Examples/tuf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchcord/FetchCord/3833c0f1464fb5703e712db4ebf0e7f88f22a829/Examples/tuf.png -------------------------------------------------------------------------------- /Examples/ubuntu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchcord/FetchCord/3833c0f1464fb5703e712db4ebf0e7f88f22a829/Examples/ubuntu.png -------------------------------------------------------------------------------- /Examples/windows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchcord/FetchCord/3833c0f1464fb5703e712db4ebf0e7f88f22a829/Examples/windows.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 MrPotatoBobx 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. 22 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include *.py 2 | include */*.py 3 | include */*/*.py 4 | include */*/*/*.py -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

FetchCord

2 |

3 |

4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 16 | 17 | 18 |

19 | 20 | # Table of content 21 | - [**Features**](#features) 22 | - [**To-Do**](#to-do) 23 | + **Installing** 24 | - [Install on (gnu/)linux](#installing-on-gnulinux) 25 | - [Install on MacOS](#installing-on-macos) 26 | - [Install on Windows](#installing-on-windows) 27 | + **Running** 28 | - [Running on (gnu/)linux](#run) 29 | - [Running on MacOS](#run-1) 30 | - [Running on Windows](#run-2) 31 | - [**Configuration**](#Configuration) 32 | - [**Arguments**](#arguments) 33 | - [**Website**](#website) 34 | 35 | + [**Examples**](#examples) 36 | 37 | ### Features 38 | 39 | - [x] Distribution detection 40 | 41 | - [x] Distribution Version 42 | 43 | - [x] Package detection 44 | 45 | - [x] Kernel Detection 46 | 47 | - [x] Uptime 48 | 49 | - [x] Detecting Window Manager/Desktop Environment 50 | 51 | - [x] Detecting GPU/CPU and display it in a cycle (thanks to Hyper-KVM) 52 | 53 | - [x] Flatpak support 54 | 55 | - [x] Add Snap support 56 | 57 | - [x] Add Windows support. 58 | 59 | - [x] Detect Window Manager/Desktop Environment version 60 | 61 | - [x] Periodic polling of info such as package count, RAM usage, etc. 62 | 63 | 64 | ### To-Do 65 | 66 | - [ ] Add more distributions (If your distro is not supported open an issue) 67 | 68 | - [ ] Add support for desktop icon use 69 | 70 | - [ ] More CPUs, ex. Pentium, Older AMD CPUs 71 | 72 | - [ ] More GPUs? 73 | 74 | 75 | ## Installing on (GNU/)Linux 76 | NOTE: you need neofetch to be also installed for this to work. 77 | #### Via AUR 78 | On Arch Linux for the git testing version (the less stable version): [fetchcord-testing](https://aur.archlinux.org/packages/fetchcord-testing/) 79 | 80 | And the git version (synced with master): [fetchcord](https://aur.archlinux.org/packages/fetchcord/) 81 | 82 | Historically the stabler release was the one from [pip](#via-pip) but now master will have only the stable releases. 83 | #### Via Snap 84 | On systems with snap installed, you can run `sudo snap install fetchcord --classic` to install fetchcord. 85 | 86 | Note that like the AUR version, this version is directly from master, for the stable release use [pip](#via-pip) 87 | #### Via pip 88 | To Install fetchcord via pip you can run `pip3 install fetchcord` 89 | 90 | If you want to remove FetchCord you can run `pip3 uninstall fetchcord` 91 | 92 | ### Run 93 | 94 | Once installed, simply run `fetchcord`. The program is also daemonizable meaning you can start it on boot using any method you prefer. 95 | 96 | If you get `fetchcord: command not found`,add `export PATH="$HOME/.local/bin:$PATH"` to your bashrc, or just run `python3 -m fetchcord`. 97 | 98 | Optionally for systemd users there is a user-side `fetchcord.service` in this repo that can be installed to `~/.local/share/systemd/user/`, started and enabled on boot using `systemctl --user enable --now fetchcord`. 99 | 100 | ## Installing on MacOS 101 | 102 | To install FetchCord, run `pip3 install FetchCord` 103 | 104 | NOTE: you need neofetch to be also installed for this to work. 105 | 106 | ### Run 107 | 108 | simply run `fetchcord` 109 | 110 | ## Installing on Windows 111 | 112 | To install fetchcord on Windows run `python -m pip install fetchcord neofetch-win`. Alternatively, you can use the neofetch package from scoop as well (show more info at the expense of possible GPU detection, for now). 113 | 114 | ### Run 115 | To run Fetchcord run `fetchcord` 116 | 117 | ### Configuration 118 | 119 | On Linux you can use the neofetch config file to: 120 | 121 | Show disk usage 122 | 123 | Battery level 124 | 125 | CPU temp 126 | 127 | Current CPU speed 128 | 129 | Font 130 | 131 | Theme 132 | 133 | And more 134 | 135 | default config path should be `~/.config/neofetch/config.conf` 136 | 137 | ## Arguments 138 | --nodistro, Don't show distro info. 139 | 140 | --nohardware, Don't show hardware info. 141 | 142 | --noshell, Don't show shell/terminal info. 143 | 144 | --nohost, Don't show host info. 145 | 146 | --time, -t, set custom duration for cycles in seconds. 147 | 148 | --terminal, set custom terminal (useful if using a script or dmenu). 149 | 150 | --termfont, set custom terminal font (useful if neofetch can't get it). 151 | 152 | --pause-cycle, Extra cycle that pauses FetchCord to show other activities. 153 | 154 | --update, Update database of distros, hardware, etc. 155 | 156 | --debug, For debug logs. 157 | 158 | --memtype, use GB or MB to show RAM. 159 | 160 | -h or --help, shows this information above. 161 | 162 | ## Website 163 | 164 | Fetchcord now has a website! You can find this site over at https://fetchcord.github.io/ - please keep in mind this site is still currently work in progress though. 165 | 166 | ## Examples 167 | 168 | ### Operating Systems 169 | ![MacOS bigsur](Examples/mac.png) ![Windows 10](Examples/windows.png) ![Ubuntu](Examples/ubuntu.png) 170 | ### Terminals 171 | ![Konsole](Examples/konsole.png) ![Gnome terminal](Examples/gnometerm.png) ![Apple terminal](Examples/appleterm.png) 172 | ### Cpus 173 | ![Ryzen 9](Examples/ryzencpu.png) ![Intel i7](Examples/intelcpu.png) ![Intel pentium](Examples/pent.png) 174 | ### Hosts 175 | ![HP laptop](Examples/hp.png) ![TUF gaming laptop](Examples/tuf.png) ![Lenovo desktop](Examples/len.png) 176 | -------------------------------------------------------------------------------- /discord.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | while true; do 3 | pid=$(ps ax | grep -i "fetchcord" | grep -v grep | awk '{print $1}') 4 | if [ ! -z "$pid" ]; then 5 | kill -15 $pid 6 | fi 7 | fetchcord & 8 | /opt/Discord/Discord & 9 | if [ $? -eq 0 ]; then 10 | exit 11 | fi 12 | sleep 25 13 | done 14 | -------------------------------------------------------------------------------- /fetch_cord.conf: -------------------------------------------------------------------------------- 1 | [cycle_0] 2 | 3 | # Order to set info in discord presence, valid values are: kernel, packages 4 | top_line=kernel 5 | bottom_line=packages 6 | # show small_icon in Discord 7 | de_wm_icon=on 8 | 9 | # Duration to show this cycle 10 | # valid values are, 15, 30, 45, 60, 75, 90, 105, 120, 240, and 480 11 | time=30 12 | 13 | [cycle_1] 14 | 15 | # Order to set info in discord presence, valid values are: mem, gpu, cpu, and disk 16 | top_line=mem 17 | bottom_line=gpu 18 | # show small_icon in Discord 19 | gpu_icon=on 20 | 21 | # Duration to show this cycle 22 | # valid values are, 15, 30, 45, 60, 75, 90, 105, 120, 240, and 480 23 | time=30 24 | 25 | [cycle_2] 26 | 27 | # Order to set info in discord presence, valid values are: font, shell, and theme 28 | top_line=font 29 | bottom_line=shell 30 | # show small_icon in Discord 31 | shell_icon=on 32 | 33 | # Duration to show this cycle 34 | # valid values are, 15, 30, 45, 60, 75, 90, 105, 120, 240, and 480 35 | time=30 36 | 37 | [cycle_3] 38 | 39 | # Order to set info in discord presence, valid values are: battery, resolution, and host 40 | top_line=battery 41 | bottom_line=resolution 42 | # show small_icon in Discord 43 | lapordesk_icon=on 44 | 45 | # Duration to show this cycle 46 | # valid values are, 15, 30, 45, 60, 75, 90, 105, 120, 240, and 480 47 | time=30 48 | -------------------------------------------------------------------------------- /fetch_cord/Cycle.py: -------------------------------------------------------------------------------- 1 | from .computer.Computer import Computer 2 | from typing import Dict 3 | 4 | 5 | class Cycle: 6 | name: str 7 | 8 | top_line: str = None 9 | bottom_line: str = None 10 | small_icon: str = None 11 | 12 | def __init__(self, name: str, config: Dict[str, str], computer: Computer): 13 | self.name = name 14 | 15 | if "top_line" in config["top_line"]: 16 | self.top_line = config["top_line"] 17 | if "bottom_line" in config["bottom_line"]: 18 | self.bottom_line = config["bottom_line"] 19 | if "small_icon" in config["small_icon"]: 20 | self.small_icon = config["small_icon"] -------------------------------------------------------------------------------- /fetch_cord/Logger.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import logging 3 | from logging.handlers import TimedRotatingFileHandler 4 | 5 | class Logger(logging.Logger): 6 | FORMATTER = logging.Formatter( 7 | "%(asctime)s - %(name)s - %(levelname)s - %(message)s" 8 | ) 9 | 10 | file: str 11 | console_handler: logging.StreamHandler 12 | file_handler: TimedRotatingFileHandler 13 | 14 | def get_console_handler() -> logging.StreamHandler: 15 | console_handler = logging.StreamHandler(sys.stdout) 16 | console_handler.setFormatter(Logger.FORMATTER) 17 | 18 | return console_handler 19 | 20 | def get_file_handler(file: str) -> TimedRotatingFileHandler: 21 | file_handler = TimedRotatingFileHandler(file, when="midnight") 22 | file_handler.setFormatter(Logger.FORMATTER) 23 | 24 | return file_handler 25 | 26 | def __init__(self, file: str, name: str, level: int = logging.INFO): 27 | super().__init__(logging.getLogger(name)) 28 | 29 | self.file = file 30 | self.console_handler = Logger.get_console_handler() 31 | self.file_handler = Logger.get_file_handler(file) 32 | 33 | self.setLevel(level) 34 | self.addHandler(self.console_handler) 35 | self.addHandler(self.file_handler) 36 | 37 | self.propagate = False -------------------------------------------------------------------------------- /fetch_cord/__init__.py: -------------------------------------------------------------------------------- 1 | VERSION = "2.7.7" -------------------------------------------------------------------------------- /fetch_cord/__main__.py: -------------------------------------------------------------------------------- 1 | # from __future__ import annotations 2 | 3 | from typing import Dict 4 | import sys, os 5 | 6 | from .run_rpc import Run_rpc 7 | from .cycles import cycle0, cycle1, cycle2, cycle3, runmac, windows, pause 8 | from .computer.Computer import Computer 9 | from .args import parse_args 10 | from .debugger import run_rpc_debug 11 | from .update import update 12 | from . import __init__ as __init__ 13 | from .resources import systemd_service 14 | 15 | 16 | def main(): 17 | args = parse_args() 18 | 19 | if args.update: 20 | update() 21 | if os.name != "nt" and sys.platform != "darwin": 22 | if args.install: 23 | systemd_service.install() 24 | if args.uninstall: 25 | systemd_service.uninstall() 26 | if args.enable: 27 | systemd_service.enable() 28 | if args.disable: 29 | systemd_service.disable() 30 | if args.start: 31 | systemd_service.start() 32 | if args.stop: 33 | systemd_service.stop() 34 | if args.status: 35 | systemd_service.status() 36 | if args.version: 37 | print("FetchCord version:", __init__.VERSION) 38 | sys.exit(0) 39 | if args.time: 40 | if int(args.time) < 15: 41 | print("ERROR: Invalid time set, must be > 15 seconds, cannot continue.") 42 | sys.exit(1) 43 | else: 44 | print("setting custom time %s seconds" % args.time) 45 | try: 46 | if args.help: 47 | sys.exit(0) 48 | except AttributeError: 49 | pass 50 | 51 | computer: Computer = Computer() 52 | 53 | if ( 54 | not computer.neofetchwin 55 | and computer.host == "Host: N/A" 56 | and args.nodistro 57 | and args.noshell 58 | and args.nohardware 59 | ): 60 | print("ERROR: no hostline is available!") 61 | sys.exit(1) 62 | # printing info with debug switch 63 | if args.debug: 64 | run_rpc_debug(computer) 65 | 66 | run: Run_rpc = Run_rpc() 67 | 68 | if computer.neofetchwin: 69 | # wandowz 70 | loops: Dict = {} 71 | loops_indexes: Dict = {} 72 | 73 | if not args.nodistro: 74 | loops["windows"] = (computer.osinfoid, windows) 75 | loops_indexes[len(loops_indexes)] = "windows" 76 | if not args.nohardware: 77 | loops["cycle1"] = (computer.cpuid, cycle1) 78 | loops_indexes[len(loops_indexes)] = "cycle1" 79 | 80 | run.set_loop( 81 | loops, 82 | loops_indexes, 83 | computer.updateMap, 84 | int(args.poll_rate) if args.poll_rate else 3, 85 | ) 86 | run.run_loop(computer) 87 | else: 88 | # loonix 89 | loops: Dict = {} 90 | loops_indexes: Dict = {} 91 | 92 | if not args.nodistro and computer.os != "macos": 93 | loops["cycle0"] = (computer.osinfoid, cycle0) 94 | loops_indexes[len(loops_indexes)] = "cycle0" 95 | if computer.os == "macos": 96 | loops["runmac"] = ("740822755376758944", runmac) 97 | loops_indexes[len(loops_indexes)] = "runmac" 98 | if not args.nohardware: 99 | loops["cycle1"] = (computer.cpuid, cycle1) 100 | loops_indexes[len(loops_indexes)] = "cycle1" 101 | if not args.noshell: 102 | loops["cycle2"] = (computer.terminalid, cycle2) 103 | loops_indexes[len(loops_indexes)] = "cycle2" 104 | if not args.nohost and computer.os != "macos": 105 | loops["cycle3"] = (computer.hostappid, cycle3) 106 | loops_indexes[len(loops_indexes)] = "cycle3" 107 | if args.pause_cycle: 108 | loops["pause"] = ("", pause) 109 | loops_indexes[len(loops_indexes)] = "pause" 110 | 111 | run.set_loop( 112 | loops, 113 | loops_indexes, 114 | computer.updateMap, 115 | int(args.poll_rate) if args.poll_rate else 3, 116 | ) 117 | run.run_loop(computer) 118 | 119 | 120 | if __name__ == "__main__": 121 | main() -------------------------------------------------------------------------------- /fetch_cord/args.py: -------------------------------------------------------------------------------- 1 | # from __future__ import annotations 2 | 3 | import argparse 4 | 5 | 6 | def parse_args(): 7 | 8 | parser = argparse.ArgumentParser( 9 | description="Fetch Cord\n" "https://github.com/MrPotatoBobx/FetchCord" 10 | ) 11 | parser.add_argument( 12 | "--nodistro", action="store_true", help="Don't show distro info." 13 | ) 14 | parser.add_argument( 15 | "--nohardware", action="store_true", help="Don't show hardware info." 16 | ) 17 | parser.add_argument( 18 | "--noshell", action="store_true", help="Don't show shell/terminal info." 19 | ) 20 | parser.add_argument("--nohost", action="store_true", help="Don't show host info.") 21 | parser.add_argument( 22 | "--noconfig", 23 | action="store_true", 24 | help="Disable neofetch custom config. Enable if you have an incompatible custom configuration.", 25 | ) 26 | parser.add_argument( 27 | "--time", 28 | "-t", 29 | metavar="TIME", 30 | action="store", 31 | help="Set custom time in seconds for cycles. Default is 30 seconds", 32 | ) 33 | parser.add_argument( 34 | "--terminal", 35 | metavar="TERMINAL", 36 | action="store", 37 | help="Set custom Terminal (useful if using something like dmenu, or launching from a script).", 38 | ) 39 | parser.add_argument( 40 | "--termfont", 41 | metavar="TERMFONT", 42 | action="store", 43 | help="Set custom Terminal Font (useful if neofetch can't get it).", 44 | ) 45 | parser.add_argument( 46 | "--install", 47 | action="store_true", 48 | help="Install fetchcord as a systemd service (user) and enable it.", 49 | ) 50 | parser.add_argument( 51 | "--uninstall", 52 | action="store_true", 53 | help="Uninstall fetchcord as a systemd service (user).", 54 | ) 55 | parser.add_argument( 56 | "--enable", 57 | action="store_true", 58 | help="Enable fetchcord systemd service (user).", 59 | ) 60 | parser.add_argument( 61 | "--disable", 62 | action="store_true", 63 | help="Disable fetchcord systemd service (user).", 64 | ) 65 | parser.add_argument( 66 | "--start", 67 | action="store_true", 68 | help="Start fetchcord systemd service (user).", 69 | ) 70 | parser.add_argument( 71 | "--stop", 72 | action="store_true", 73 | help="Stop fetchcord systemd service (user).", 74 | ) 75 | parser.add_argument( 76 | "--status", 77 | action="store_true", 78 | help="Get fetchcord systemd service status (user).", 79 | ) 80 | parser.add_argument( 81 | "--update", 82 | action="store_true", 83 | help="Update database of distros, hardware, etc.", 84 | ) 85 | parser.add_argument( 86 | "--testing", 87 | action="store_true", 88 | help="Get files from testing branch instead of master.", 89 | ) 90 | parser.add_argument("--debug", "-d", action="store_true", help="Enable debugging.") 91 | parser.add_argument( 92 | "--pause-cycle", 93 | "-p", 94 | action="store_true", 95 | help="Extra cycle that pauses for 30 seconds or custom time using --time argument.", 96 | ) 97 | parser.add_argument( 98 | "--memtype", 99 | "-m", 100 | metavar="TYPE", 101 | action="store", 102 | help="Show Memory in GiB or MiB. Valid vaules are 'gb', 'mb'", 103 | ) 104 | parser.add_argument( 105 | "--poll-rate", 106 | "-r", 107 | metavar="RATE", 108 | action="store", 109 | help="Set info polling rate.", 110 | ) 111 | parser.add_argument( 112 | "--version", "-v", action="store_true", help="Print FetchCord Version." 113 | ) 114 | parser.add_argument( 115 | "--config-path", 116 | "-c", 117 | action="store", 118 | help="Specify custom neofetch config path.", 119 | ) 120 | parser.add_argument( 121 | "--fetchcord-config-path", 122 | "-fc", 123 | action="store", 124 | help="Specify custom fetchcord config path.", 125 | ) 126 | parser.add_argument( 127 | "--nfco", 128 | "-nfco", 129 | action="store", 130 | help="nfco", 131 | ) 132 | 133 | return parser.parse_args() 134 | -------------------------------------------------------------------------------- /fetch_cord/computer/Computer.py: -------------------------------------------------------------------------------- 1 | # from __future__ import annotations 2 | 3 | import logging 4 | from sys import platform, exit 5 | import sys 6 | from typing import Callable, Dict, List 7 | import psutil, os 8 | 9 | from ..run_command import exec_bash, run_command 10 | from ..args import parse_args 11 | from ..Logger import Logger 12 | from .flatpak import enableFlatpak 13 | from .resources import get_infos, get_default_config 14 | from .cpu.get_cpu import get_cpu 15 | from .cpu.Cpu_interface import Cpu_interface 16 | from .gpu.get_gpu import get_gpu 17 | from .gpu.Gpu_interface import GpuType, get_gpuid 18 | from .mobo.get_mobo import get_mobo 19 | 20 | args = parse_args() 21 | 22 | # logger = Logger( 23 | # "fetchcord_computer.log", 24 | # "fetchcord_computer", 25 | # logging.DEBUG if args.debug else logging.INFO, 26 | # ) 27 | 28 | 29 | class Computer: 30 | parseMap: Dict[str, Callable] 31 | componentMap: Dict[str, List] = {} 32 | idsMap: Dict[str, Dict] 33 | 34 | os: str 35 | neofetchwin: bool = False 36 | neofetch: bool = False 37 | values: str 38 | laptop: bool = False 39 | uptime: float 40 | 41 | @property 42 | def memory(self) -> str: 43 | return self.get_component_line("Memory:") 44 | 45 | @property 46 | def osinfo(self) -> str: 47 | return self.get_component_line("OS:") 48 | 49 | @property 50 | def osinfoid(self) -> str: 51 | component = self.get_component_line("OS:") 52 | component = (component.split()[0] + component.split()[1]).lower() 53 | component_list = self.idsMap[self.idsMap["map"]["OS:"]] 54 | 55 | for comp, id in component_list.items(): 56 | if component.lower().find(comp.lower()) >= 0: 57 | return id 58 | 59 | print( 60 | "Unknown {}, contact us on github to resolve this.".format( 61 | self.idsMap["map"]["OS:"] 62 | ) 63 | ) 64 | 65 | return component_list["unknown"] 66 | 67 | @property 68 | def motherboard(self) -> str: 69 | tmp = self.get_component_line("Motherboard:") 70 | if tmp == "Motherboard: N/A": 71 | return self.host 72 | 73 | return tmp 74 | 75 | @property 76 | def motherboardid(self) -> str: 77 | return self.get_component_idkey("Motherboard:") 78 | 79 | @property 80 | def motherboardappid(self) -> str: 81 | tmp = self.get_component_id("Motherboard:") 82 | 83 | if tmp == self.idsMap[self.idsMap["map"]["Motherboard:"]]["unknown"]: 84 | return self.hostappid 85 | 86 | return tmp 87 | 88 | @property 89 | def host(self) -> str: 90 | return self.get_component_line("Host:") 91 | 92 | @property 93 | def hostid(self) -> str: 94 | hostsplit = self.host.split() 95 | host_list: Dict[str, str] = self.idsMap[self.idsMap["map"]["Host:"]] 96 | 97 | for line in hostsplit: 98 | if line in host_list: 99 | return line 100 | 101 | # try to get MacBook hostid 102 | hostid = [] 103 | hostjoin = " ".join(self.host) 104 | for numsplit in range(len(hostjoin)): 105 | if not hostjoin[numsplit].isdigit(): 106 | hostid.append(hostjoin[numsplit]) 107 | hostid = "".join(hostid) 108 | hostid = hostid.split()[1] 109 | 110 | if hostid in host_list: 111 | return host_list[hostid] 112 | else: 113 | return host_list["unknown"] 114 | 115 | @property 116 | def hostappid(self) -> str: 117 | return self.get_component_id("Host:") 118 | 119 | @property 120 | def cpu(self) -> str: 121 | key = "CPU:" 122 | cpus: List[Cpu_interface] = self.get_component(key) 123 | temp = [] 124 | for cpu in cpus: 125 | temp.append(cpu.info) 126 | 127 | return "\n".join(temp) if len(cpus) > 0 else "{} N/A".format(key) 128 | 129 | @property 130 | def cpuid(self) -> str: 131 | temp: List[Cpu_interface] = self.get_component("CPU:") 132 | 133 | if len(temp) == 0: 134 | return self.idsMap[self.idsMap["map"]["CPU:"]]["unknown"] 135 | else: 136 | return temp[0].get_id(self.idsMap[self.idsMap["map"]["CPU:"]]) 137 | 138 | @property 139 | def gpu(self) -> str: 140 | key = "GPU:" 141 | gpus: List[GpuType] = self.get_component(key) 142 | temp = [] 143 | for gpu in gpus: 144 | if gpu.vendor == "amd" and self.os == "linux": 145 | temp.append(gpu.get_amdgpurender(gpus, self.laptop).rstrip().lstrip()) 146 | else: 147 | temp.append(gpu.model.lstrip().rstrip()) 148 | 149 | return "\n".join(temp) if len(gpus) > 0 else "{} N/A".format(key) 150 | 151 | @property 152 | def gpuid(self) -> str: 153 | return get_gpuid( 154 | self.idsMap[self.idsMap["map"]["GPU:"]], self.get_component("GPU:") 155 | ) 156 | 157 | @property 158 | def disks(self) -> str: 159 | return self.get_component_line("Disk") 160 | 161 | @property 162 | def resolution(self) -> str: 163 | return self.get_component_line("Resolution:") 164 | 165 | @property 166 | def theme(self) -> str: 167 | return self.get_component_line("Theme:") 168 | 169 | @property 170 | def kernel(self) -> str: 171 | return self.get_component_line("Kernel:") 172 | 173 | @property 174 | def packages(self) -> str: 175 | return self.get_component_line("Packages:") 176 | 177 | @property 178 | def shell(self) -> str: 179 | return self.get_component_line("Shell:") 180 | 181 | @property 182 | def shellid(self) -> str: 183 | return self.get_component_id("Shell:") 184 | 185 | @property 186 | def terminal(self) -> str: 187 | return self.get_component_line("Terminal:") 188 | 189 | @property 190 | def terminalid(self) -> str: 191 | return self.get_component_id("Terminal:") 192 | 193 | @property 194 | def wm(self) -> str: 195 | return self.get_component_line("WM:") 196 | 197 | @property 198 | def wmid(self) -> str: 199 | return self.get_component_line("WM:").split()[0] 200 | 201 | @property 202 | def font(self) -> str: 203 | return self.get_component_line("Font:") 204 | 205 | @property 206 | def de(self) -> str: 207 | return self.get_component_line("DE:") 208 | 209 | @property 210 | def deid(self) -> str: 211 | value = self.get_component_line("DE:").split()[0] 212 | 213 | return "n/a" if value == "DE:" else value 214 | 215 | @property 216 | def dewmid(self) -> str: 217 | de = self.get_component_line("DE:") 218 | 219 | return "\n".join( 220 | ["" if de == "{} N/A".format("DE:") else de, self.get_component_line("WM:")] 221 | ) 222 | 223 | @property 224 | def desktopid(self) -> str: 225 | deid = self.deid.lower() 226 | wmid = self.wmid.lower() 227 | 228 | if deid == "unity": 229 | if wmid == "compiz": 230 | return "unity" 231 | else: 232 | return wmid 233 | 234 | if deid != "n/a" and deid in self.idsMap[self.idsMap["map"]["DE:"]]: 235 | return deid 236 | elif deid == "n/a" and wmid in self.idsMap[self.idsMap["map"]["WM:"]]: 237 | return wmid 238 | else: 239 | print("Unknown DE/WM, contact us on github to resolve this.") 240 | return "unknown" 241 | 242 | @property 243 | def battery(self) -> str: 244 | if self.laptop: 245 | return self.get_component_line("Battery") 246 | else: 247 | return "{} N/A".format("Battery") 248 | 249 | @property 250 | def lapordesk(self) -> str: 251 | if self.laptop and self.os != "macos": 252 | return "laptop" 253 | else: 254 | return "desktop" 255 | 256 | @property 257 | def version(self) -> str: 258 | return os.popen("sw_vers -productVersion").read() 259 | 260 | @property 261 | def product(self) -> str: 262 | return os.popen("sysctl -n hw.model").read() 263 | 264 | @property 265 | def devicetype(self) -> str: 266 | if self.product[0:7] == "MacBook": 267 | return "laptop" 268 | else: 269 | return "desktop" 270 | 271 | @property 272 | def bigicon(self) -> str: 273 | try: 274 | return self.idsMap[self.idsMap["map"]["Version:"]][self.version[0:5]] 275 | except KeyError: 276 | print("Unsupported MacOS version") 277 | return "bigslurp" 278 | 279 | def __init__(self): 280 | super().__init__() 281 | 282 | self.parseMap = { 283 | "CPU:": get_cpu, 284 | "GPU:": get_gpu, 285 | "Disk": self.get_disk, 286 | "Memory:": self.get_memory, 287 | "OS:": self.get, 288 | "Motherboard:": get_mobo, 289 | "Host:": self.get, 290 | "Resolution:": self.get, 291 | "Theme:": self.get, 292 | "Kernel:": self.get, 293 | "Packages:": self.get, 294 | "Shell:": self.get, 295 | "Terminal:": self.get, 296 | "Font:": self.get, 297 | "DE:": self.get, 298 | "WM:": self.get, 299 | "Battery": self.get_battery, 300 | } 301 | 302 | self.idsMap = get_infos() 303 | self.uptime = psutil.boot_time() 304 | 305 | self.detect_os() 306 | self.detect_laptop() 307 | 308 | self.fetch_values() 309 | 310 | def fetch_values(self): 311 | self.neofetchwin, self.neofetch, self.values = self.detect_neofetch() 312 | 313 | self.neofetch_parser(self.values) 314 | 315 | if not bool(self.componentMap): 316 | args.config_path = "" 317 | args.noconfig = False 318 | 319 | self.neofetchwin, self.neofetch, self.values = self.detect_neofetch() 320 | self.neofetch_parser(self.values) 321 | 322 | terminallist = self.idsMap[self.idsMap["map"]["Terminal:"]] 323 | if args.terminal and args.terminal.lower() in terminallist: 324 | self.componentMap["Terminal:"] = [args.terminal.lower()] 325 | elif args.terminal and args.terminal.lower() not in terminallist: 326 | print( 327 | "\nInvalid terminal, only %s are supported.\n" 328 | "Please make a github issue if you would like to have your terminal added.\n" 329 | "https://github.com/MrPotatoBobx/FetchCord" % terminallist 330 | ) 331 | sys.exit(1) 332 | 333 | if self.get_component("Font:", True) and args.termfont: 334 | print( 335 | "Custom terminal font not set because a terminal font already exists, %s" 336 | % self.font 337 | ) 338 | elif not self.get_component("Font:", True) and args.termfont: 339 | self.componentMap["Font:"] = [args.termfont] 340 | 341 | def updateMap(self): 342 | """ 343 | Clear the components values and fetch new ones 344 | """ 345 | self.clearMap() 346 | self.neofetchwin, self.neofetch, self.values = self.detect_neofetch() 347 | self.neofetch_parser(self.values) 348 | 349 | def clearMap(self): 350 | """ 351 | Clear the components values 352 | """ 353 | for key in self.componentMap.keys(): 354 | del self.componentMap[key][:] 355 | 356 | def neofetch_parser(self, values: str): 357 | if args.debug: 358 | print(values) 359 | lines = values.split("\n") 360 | for i in range(len(lines)): 361 | line = lines[i] 362 | for key, detectedFunction in [ 363 | (key, value) for key, value in self.parseMap.items() if key in line 364 | ]: 365 | if key not in self.componentMap: 366 | self.componentMap[key] = [] 367 | detectedFunction( 368 | self.os, self.componentMap[key], line.rstrip("\n"), key 369 | ) 370 | 371 | def detect_os(self) -> str: 372 | if platform == "linux" or platform == "linux2": 373 | self.os = "linux" 374 | elif platform == "darwin": 375 | self.os = "macos" 376 | elif platform == "win32": 377 | self.os = "windows" 378 | else: 379 | raise Exception("Not a supported OS !") 380 | 381 | return self.os 382 | 383 | def detect_laptop(self) -> bool: 384 | if self.os != "linux": 385 | self.laptop = False 386 | else: 387 | for i in os.listdir("/sys/class/power_supply"): 388 | if i.startswith("BAT"): 389 | self.laptop = True 390 | break 391 | 392 | return self.laptop 393 | 394 | def detect_neofetch(self): 395 | neofetchwin = False 396 | neofetch = False 397 | values = None 398 | 399 | if self.os == "windows": 400 | try: 401 | values = run_command(["neofetch", "--noart"]) 402 | if args.nfco: 403 | with open(args.nfco) as f: 404 | values = "\n".join(f.readlines()) 405 | 406 | except Exception: 407 | pass 408 | else: 409 | neofetchwin = True 410 | if not neofetchwin: 411 | if self.os == "linux": 412 | enableFlatpak() 413 | 414 | default_config = get_default_config() 415 | 416 | try: 417 | if self.os == "windows": 418 | values = run_command( 419 | [ 420 | "neofetch", 421 | "--config {}".format( 422 | "none" 423 | if args.noconfig 424 | else ( 425 | args.config_path 426 | if args.config_path 427 | else (default_config) 428 | ) 429 | ), 430 | "--stdout", 431 | ], 432 | shell=(self.os == "windows"), 433 | ) 434 | else: 435 | values = exec_bash( 436 | "neofetch --config {} --stdout".format( 437 | "none" 438 | if args.noconfig 439 | else ( 440 | args.config_path 441 | if args.config_path 442 | else (default_config) 443 | ) 444 | ) 445 | ) 446 | if args.nfco: 447 | with open(args.nfco) as f: 448 | values = "\n".join(f.readlines()) 449 | 450 | except Exception: 451 | print( 452 | "ERROR: Neofetch not found, please install it or check installation and that neofetch is in PATH." 453 | ) 454 | exit(1) 455 | else: 456 | neofetch = True 457 | 458 | return (neofetchwin, neofetch, values) 459 | 460 | def get_battery(self, os: str, line: List, value: str, key: str): 461 | """ 462 | Append the Battery info from given neofetch line 463 | 464 | Parameters 465 | ---------- 466 | value : str 467 | Neofetch extracted line 468 | """ 469 | 470 | line.append(value[value.find(key) + len(key) + 2 :]) 471 | 472 | def get_disk(self, os: str, line: List, value: str, key: str): 473 | """ 474 | Append the Disk info from the given neofetch line to the Disk list 475 | 476 | Parameters 477 | ---------- 478 | value : str 479 | Neofetch extracted line 480 | """ 481 | 482 | line.append(value[value.find(key) + len(key) + 2 :]) 483 | 484 | def get_memory(self, os: str, line: List, value: str, key: str): 485 | """ 486 | Get the memory info from the given neofetch line 487 | 488 | Parameters 489 | ---------- 490 | value : str 491 | Neofetch extracted line 492 | """ 493 | 494 | if args.memtype == "gb": 495 | memgb = value.split() 496 | used = float(memgb[1].replace("MiB", "")) 497 | total = float(memgb[3].replace("MiB", "")) 498 | 499 | line.append( 500 | " ".join( 501 | [ 502 | str(round(used / 1024, 2)), 503 | "GiB /", 504 | str(round(total / 1024, 2)), 505 | "GiB", 506 | ] 507 | ) 508 | ) 509 | else: 510 | line.append(value[value.find(key) + len(key) + 1 :]) 511 | 512 | def get(self, os: str, line: List, value: str, key: str, valueOffset: int = 1): 513 | """ 514 | Get the info from the given neofetch line 515 | 516 | Parameters 517 | ---------- 518 | os: str 519 | Detected OS ("windows", "linux" or "macos") 520 | line: List 521 | List who will contains the values 522 | value : str 523 | Neofetch extracted line 524 | key : str 525 | Key for the dict 526 | valueOffset: int 527 | Offset for extracting the value without the key (default : 1) 528 | """ 529 | 530 | line.append(value[value.find(key) + len(key) + valueOffset :]) 531 | 532 | def get_component(self, key: str, quiet: bool = False): 533 | """ 534 | Get component info from map 535 | 536 | Args: 537 | key (str): component key in map 538 | """ 539 | try: 540 | return self.componentMap[key] 541 | except KeyError as err: 542 | if args.debug: 543 | print("[KeyError]: {}".format(err), end="") 544 | 545 | return [] 546 | 547 | def get_component_line(self, key: str) -> str: 548 | try: 549 | values = self.componentMap[key] 550 | return "\n".join(values) if len(values) > 0 else "{} N/A".format(key) 551 | except KeyError as err: 552 | if args.debug: 553 | print("[KeyError]: ", end="") 554 | print(err) 555 | 556 | return "{} N/A".format(key) 557 | 558 | def get_component_id(self, key: str) -> str: 559 | component = self.get_component_line(key).lower() 560 | component_list = self.idsMap[self.idsMap["map"][key]] 561 | 562 | for comp, id in component_list.items(): 563 | if component.find(comp.lower()) >= 0: 564 | return id 565 | 566 | print( 567 | "Unknown {}, contact us on github to resolve this.".format( 568 | self.idsMap["map"][key] 569 | ) 570 | ) 571 | if args.debug: 572 | print(f"Value: {component}") 573 | 574 | return component_list["unknown"] 575 | 576 | def get_component_idkey(self, key: str) -> str: 577 | component = self.get_component_line(key).lower() 578 | component_list = self.idsMap[self.idsMap["map"][key]] 579 | 580 | for comp, _ in component_list.items(): 581 | if component.find(comp.lower()) >= 0: 582 | return comp 583 | 584 | print( 585 | "Unknown {}, contact us on github to resolve this.".format( 586 | self.idsMap["map"][key] 587 | ) 588 | ) 589 | 590 | return component_list["unknown"] 591 | -------------------------------------------------------------------------------- /fetch_cord/computer/Peripheral_interface.py: -------------------------------------------------------------------------------- 1 | #from __future__ import annotations 2 | 3 | from abc import ABCMeta 4 | 5 | 6 | class Peripherical_interface(metaclass=ABCMeta): 7 | os: str 8 | 9 | def __init__(self, os): 10 | super().__init__() 11 | self.os = os -------------------------------------------------------------------------------- /fetch_cord/computer/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchcord/FetchCord/3833c0f1464fb5703e712db4ebf0e7f88f22a829/fetch_cord/computer/__init__.py -------------------------------------------------------------------------------- /fetch_cord/computer/cpu/Cpu_amd.py: -------------------------------------------------------------------------------- 1 | # from __future__ import annotations 2 | 3 | import os 4 | from sys import platform 5 | 6 | if os.name != "nt" and platform != "darwin": 7 | from psutil import sensors_temperatures 8 | from .Cpu_interface import Cpu_interface 9 | 10 | CPU_VENDOR = "amd" 11 | 12 | 13 | class Cpu_amd(Cpu_interface): 14 | def __init__(self, os, model): 15 | super().__init__(os, CPU_VENDOR, model) 16 | 17 | @Cpu_interface.model.setter 18 | def model(self, value: str): 19 | self.info = " ".join(value.split()[1:]) 20 | self._model = " ".join([value.split()[2], value.split()[3]]) 21 | 22 | if self._model.find("APU") != -1 or ( 23 | self._model.find("RADEON") != -1 and self._model.lower().find("ryzen") == -1 24 | ): 25 | self._model = f"{self._model.split('-')[0]} APU" 26 | 27 | def get_temp(self) -> float: 28 | if self.os == "windows": 29 | raise NotImplementedError( 30 | "Temperature report for AMD CPU's is not supported on Windows yet." 31 | ) 32 | elif self.os == "macos": 33 | raise NotImplementedError( 34 | "Temperature report for AMD CPU's is not supported on MacOS yet." 35 | ) 36 | elif ( 37 | self.os == "linux" # and os.name != "nt" linux only 38 | ): # os.name comparaison not needed, its just for the linter 39 | sensors = sensors_temperatures() 40 | if "k10temp" in sensors: 41 | temps = sensors["k10temp"] 42 | if len(temps) == 1: 43 | return temps.current 44 | else: 45 | for temp in temps: 46 | if temp.label == "Tdie": 47 | return temp.current 48 | 49 | raise Exception("No valid temperature value found.") 50 | 51 | raise Exception("No valid sensor found.") 52 | else: 53 | raise NotImplementedError("Unknown OS, no CPU temperature report.") 54 | -------------------------------------------------------------------------------- /fetch_cord/computer/cpu/Cpu_intel.py: -------------------------------------------------------------------------------- 1 | #from __future__ import annotations 2 | 3 | from .Cpu_interface import Cpu_interface 4 | import re 5 | 6 | CPU_VENDOR = "intel" 7 | 8 | 9 | class Cpu_intel(Cpu_interface): 10 | def __init__(self, os, model): 11 | super().__init__(os, CPU_VENDOR, model) 12 | 13 | @Cpu_interface.model.setter 14 | def model(self, value: str): 15 | self.info = " ".join(value.split()[1:]) 16 | if value.split()[1].replace("Intel(R)", "Intel") == "Pentium": 17 | self._model = value.split()[1] 18 | else: 19 | # Remove "CPU: ", "(R)" and "(TM)" 20 | self._model = " ".join( 21 | re.sub(r"\((.+)\)", "", value.replace("-", " ")).split()[1:] 22 | ) 23 | 24 | # Core 2 Duo, Core 2 Quad 25 | if self._model.find("Intel Core") != -1: 26 | self._model = " ".join(self._model.split()[:4]) 27 | else: 28 | self._model = " ".join(self._model.split()[:2]) 29 | 30 | if self._model == "Intel Core": 31 | self._model = value.split()[1:5] 32 | self._model = " ".join(self._model) 33 | 34 | def get_temp(self): 35 | if self.os == "windows": 36 | raise NotImplementedError( 37 | "Temperature report for Intel CPU's is not supported on Windows yet." 38 | ) 39 | elif self.os == "macos": 40 | raise NotImplementedError( 41 | "Temperature report for Intel CPU's is not supported on MacOS yet." 42 | ) 43 | elif self.os == "linux": 44 | raise NotImplementedError( 45 | "Temperature report for Intel CPU's is not supported on Linux yet." 46 | ) 47 | else: 48 | raise NotImplementedError("Unkown OS, no CPU temperature report.") 49 | -------------------------------------------------------------------------------- /fetch_cord/computer/cpu/Cpu_interface.py: -------------------------------------------------------------------------------- 1 | #from __future__ import annotations 2 | 3 | from abc import ABCMeta, abstractmethod 4 | from typing import Dict 5 | 6 | from ..Peripheral_interface import Peripherical_interface 7 | 8 | 9 | class Cpu_interface(Peripherical_interface, metaclass=ABCMeta): 10 | vendor: str 11 | _model: str 12 | info: str 13 | 14 | @property 15 | def model(self) -> str: 16 | return self._model 17 | 18 | @model.setter 19 | @abstractmethod 20 | def model(self, value: str): 21 | raise NotImplementedError 22 | 23 | @property 24 | def temp(self) -> float: 25 | try: 26 | self._temp = self.get_temp() 27 | except NotImplementedError as e: 28 | try: 29 | raise e 30 | finally: 31 | e = None 32 | del e 33 | 34 | else: 35 | return self._temp 36 | 37 | @temp.setter 38 | def temp(self, value: float): 39 | self._temp = value 40 | 41 | def __init__(self, os, vendor, model): 42 | super().__init__(os) 43 | self.vendor = vendor 44 | self.model = model 45 | 46 | @abstractmethod 47 | def get_temp(self) -> float: 48 | raise NotImplementedError 49 | 50 | def get_id(self, cpu_list: Dict[str, str]) -> str: 51 | if self.model.lower() in cpu_list[self.vendor]: 52 | return cpu_list[self.vendor][self.model.lower()] 53 | else: 54 | return cpu_list["unknown"] 55 | -------------------------------------------------------------------------------- /fetch_cord/computer/cpu/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchcord/FetchCord/3833c0f1464fb5703e712db4ebf0e7f88f22a829/fetch_cord/computer/cpu/__init__.py -------------------------------------------------------------------------------- /fetch_cord/computer/cpu/get_cpu.py: -------------------------------------------------------------------------------- 1 | #from __future__ import annotations 2 | 3 | from typing import List 4 | 5 | from .Cpu_amd import Cpu_amd 6 | from .Cpu_intel import Cpu_intel 7 | 8 | 9 | def get_cpu(os: str, line: List, value: str, key: str): 10 | """ 11 | Append the CPU info from the given neofetch line to the CPU list 12 | 13 | Parameters 14 | ---------- 15 | os : 16 | OS type 17 | line : List 18 | Component line 19 | value : str 20 | Neofetch extracted line 21 | key : str 22 | Component key 23 | """ 24 | 25 | vendor = value.replace(key, "").lstrip("").replace("Intel(R)", "Intel") 26 | 27 | if vendor.find("Intel") != -1 or vendor.find("Pentium") != -1: 28 | line.append(Cpu_intel(os, value)) 29 | elif vendor.find("AMD") != -1: 30 | line.append(Cpu_amd(os, value)) -------------------------------------------------------------------------------- /fetch_cord/computer/flatpak.py: -------------------------------------------------------------------------------- 1 | #from __future__ import annotations 2 | 3 | from fetch_cord.run_command import BashError, exec_bash 4 | import os 5 | 6 | 7 | def enableFlatpak(): 8 | home = os.getenv("HOME") 9 | flatpak_discord_path = os.path.isdir("%s/.var/app/com.discordapp.Discord" % home) 10 | package_path = os.path.isfile("/usr/bin/discord") 11 | manual_install_path = os.path.isdir("/opt/Discord") 12 | if flatpak_discord_path and not package_path and not manual_install_path: 13 | XDG_Symlink(home) 14 | 15 | 16 | def XDG_Symlink(home): 17 | try: 18 | print("Symlinking XDG_RUNTIME_DIR path for Flatpak Discord.") 19 | exec_bash( 20 | "cd %s/.var && ln -sf {app/com.discordapp.Discord,$XDG_RUNTIME_DIR}/discord-ipc-0 " 21 | % home 22 | ) 23 | except BashError as e: 24 | print("Could not symlink XDG_RUNTIME_DIR Error: %s" % str(e)) 25 | return 26 | -------------------------------------------------------------------------------- /fetch_cord/computer/gpu/Gpu_amd.py: -------------------------------------------------------------------------------- 1 | # from __future__ import annotations 2 | from fetch_cord.run_command import BashError, exec_bash 3 | from typing import List 4 | import sys 5 | 6 | from .Gpu_interface import Gpu_interface, GpuType 7 | 8 | GPU_VENDOR = "amd" 9 | 10 | 11 | class Gpu_amd(Gpu_interface): 12 | def __init__(self, os, model): 13 | super().__init__(os, GPU_VENDOR, model) 14 | 15 | @Gpu_interface.model.setter 16 | def model(self, value: str): 17 | self._model = value 18 | 19 | def get_temp(self): 20 | if self.os == "windows": 21 | raise NotImplementedError( 22 | "Temperature report for AMD GPU's is not supported on Windows yet." 23 | ) 24 | elif self.os == "macos": 25 | raise NotImplementedError( 26 | "Temperature report for AMD GPU's is not supported on MacOS yet." 27 | ) 28 | elif self.os == "linux": 29 | raise NotImplementedError( 30 | "Temperature report for AMD GPU's is not supported on Linux yet." 31 | ) 32 | else: 33 | raise NotImplementedError("Unknown OS, no GPU temperature report.") 34 | 35 | def get_amdgpurender(self, gpu_list: List[GpuType], laptop: bool) -> str: 36 | try: 37 | for i in range(len(gpu_list)): 38 | # assume DRI_PRIME=0 is the intel GPU 39 | if laptop and "intel" == gpu_list[i].vendor.lower(): 40 | i += 1 41 | if ( 42 | laptop 43 | and "amd" == gpu_list[i].vendor.lower() 44 | and gpu_list[i].model != self.model 45 | ): 46 | i += 1 47 | 48 | env_prime = "DRI_PRIME=%s" % i 49 | return exec_bash( 50 | "%s glxinfo | grep \"OpenGL renderer string:\" |sed 's/^.*: //;s/[(][^)]*[)]//g'" 51 | % env_prime 52 | ) 53 | except BashError as e: 54 | print("ERROR: Could not run glxinfo [%s]" % str(e)) 55 | sys.exit(1) -------------------------------------------------------------------------------- /fetch_cord/computer/gpu/Gpu_intel.py: -------------------------------------------------------------------------------- 1 | # from __future__ import annotations 2 | from .Gpu_interface import Gpu_interface 3 | 4 | GPU_VENDOR = "intel" 5 | 6 | 7 | class Gpu_intel(Gpu_interface): 8 | def __init__(self, os, model): 9 | super().__init__(os, GPU_VENDOR, model) 10 | 11 | @Gpu_interface.model.setter 12 | def model(self, value: str): 13 | self._model = value 14 | 15 | @Gpu_interface.vendor.setter 16 | def vendor(self, value: str): 17 | self._vendor = value.replace(f"{GPU_VENDOR}(R)", f"{GPU_VENDOR}") 18 | 19 | 20 | def get_temp(self): 21 | if self.os == "windows": 22 | raise NotImplementedError( 23 | "Temperature report for Intel GPU's is not supported on Windows yet." 24 | ) 25 | elif self.os == "macos": 26 | raise NotImplementedError( 27 | "Temperature report for Intel GPU's is not supported on MacOS yet." 28 | ) 29 | elif self.os == "linux": 30 | raise NotImplementedError( 31 | "Temperature report for Intel GPU's is not supported on Linux yet." 32 | ) 33 | else: 34 | raise NotImplementedError("Unknown OS, no GPU temperature report.") 35 | -------------------------------------------------------------------------------- /fetch_cord/computer/gpu/Gpu_interface.py: -------------------------------------------------------------------------------- 1 | # from __future__ import annotations 2 | from abc import ABCMeta, abstractmethod 3 | from typing import List, TypeVar, Dict 4 | 5 | from ..Peripheral_interface import Peripherical_interface 6 | 7 | 8 | class Gpu_interface(Peripherical_interface, metaclass=ABCMeta): 9 | _vendor: str 10 | _model: str 11 | 12 | @property 13 | def vendor(self) -> str: 14 | return self._vendor 15 | 16 | @vendor.setter 17 | def vendor(self, value: str): 18 | self._vendor = value 19 | 20 | @property 21 | def model(self) -> str: 22 | return self._model 23 | 24 | @model.setter 25 | @abstractmethod 26 | def model(self, value: str): 27 | raise NotImplementedError 28 | 29 | @property 30 | def temp(self) -> float: 31 | try: 32 | self._temp = self.get_temp() 33 | except NotImplementedError as e: 34 | try: 35 | raise e 36 | finally: 37 | e = None 38 | del e 39 | 40 | else: 41 | return self._temp 42 | 43 | @temp.setter 44 | def temp(self, value: float): 45 | self._temp = value 46 | 47 | def __init__(self, os, vendor, model): 48 | super().__init__(os) 49 | self.vendor = vendor 50 | self.model = model 51 | 52 | @abstractmethod 53 | def get_temp(self) -> float: 54 | raise NotImplementedError 55 | 56 | 57 | GpuType = TypeVar("GpuType", bound="Gpu_interface") 58 | 59 | 60 | def get_gpuid(gpu_ids: Dict[str, str], gpus: List[GpuType]): 61 | vendors = [] 62 | for i in range(len(gpus)): 63 | if gpus[i].vendor not in vendors: 64 | vendors.append(gpus[i].vendor) 65 | 66 | gpuvendor = "".join(vendors).lower() 67 | 68 | if gpuvendor in gpu_ids: 69 | return gpu_ids[gpuvendor] 70 | else: 71 | print("Unknown GPU, contact us on github to resolve this.") 72 | return "unknown" 73 | -------------------------------------------------------------------------------- /fetch_cord/computer/gpu/Gpu_nvidia.py: -------------------------------------------------------------------------------- 1 | # from __future__ import annotations 2 | from fetch_cord.run_command import BashError, exec_bash 3 | from .Gpu_interface import Gpu_interface 4 | 5 | GPU_VENDOR = "nvidia" 6 | 7 | 8 | class Gpu_nvidia(Gpu_interface): 9 | primeoffload: bool 10 | 11 | def __init__(self, os, model): 12 | super().__init__(os, GPU_VENDOR, model) 13 | 14 | @Gpu_interface.model.setter 15 | def model(self, value: str): 16 | self._model = value 17 | 18 | def get_temp(self): 19 | if self.os == "windows": 20 | raise NotImplementedError( 21 | "Temperature report for Nvidia GPU's is not supported on Windows yet." 22 | ) 23 | elif self.os == "macos": 24 | raise NotImplementedError( 25 | "Temperature report for Nvidia GPU's is not supported on MacOS yet." 26 | ) 27 | elif self.os == "linux": 28 | try: 29 | return exec_bash( 30 | "nvidia-smi -q | awk '/GPU Current Temp/{print $5}' | sed 's/^/[/;s/$/°C]/'" 31 | ) 32 | except BashError: 33 | pass 34 | else: 35 | raise NotImplementedError("Unknown OS, no GPU temperature report.") 36 | 37 | def check_primeoffload(self): 38 | # only show the GPU in use with optimus, show both if prime render offload 39 | self.primeoffload = False 40 | try: 41 | self.primeoffload = exec_bash('xrandr --listproviders | grep -o "NVIDIA-0"') 42 | return True 43 | except BashError: 44 | return False -------------------------------------------------------------------------------- /fetch_cord/computer/gpu/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchcord/FetchCord/3833c0f1464fb5703e712db4ebf0e7f88f22a829/fetch_cord/computer/gpu/__init__.py -------------------------------------------------------------------------------- /fetch_cord/computer/gpu/get_gpu.py: -------------------------------------------------------------------------------- 1 | # from __future__ import annotations 2 | from typing import List 3 | 4 | from .Gpu_amd import Gpu_amd 5 | from .Gpu_nvidia import Gpu_nvidia 6 | from .Gpu_intel import Gpu_intel 7 | 8 | 9 | def get_gpu(os: str, line: List, value: str, key: str): 10 | """ 11 | Append the GPU info from the given neofetch line to the GPU list 12 | 13 | Parameters 14 | ---------- 15 | os : 16 | OS type 17 | line : List 18 | Component line 19 | value : str 20 | Neofetch extracted line 21 | key : str 22 | Component key 23 | """ 24 | 25 | value = value.replace(key, "").lstrip() 26 | splitValue = value.split() 27 | 28 | for v in splitValue: 29 | if v.upper() in ["AMD", "RADEON"]: 30 | line.append(Gpu_amd(os, value)) 31 | return 32 | elif v.upper() in ["NVIDIA", "GEFORCE"]: 33 | line.append(Gpu_nvidia(os, value)) 34 | return 35 | elif v.upper() in ["INTEL", "INTEL(R)"]: 36 | line.append(Gpu_intel(os, value)) 37 | return -------------------------------------------------------------------------------- /fetch_cord/computer/mobo/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchcord/FetchCord/3833c0f1464fb5703e712db4ebf0e7f88f22a829/fetch_cord/computer/mobo/__init__.py -------------------------------------------------------------------------------- /fetch_cord/computer/mobo/get_mobo.py: -------------------------------------------------------------------------------- 1 | from fetch_cord.run_command import exec_bash 2 | from typing import List 3 | 4 | 5 | def get_mobo(os: str, line: List, value: str, key: str): 6 | if(os == "linux"): 7 | line.append(exec_bash("cat /sys/devices/virtual/dmi/id/board_vendor")) 8 | else: 9 | line.append(value[value.find(key) + len(key) + 1 :]) -------------------------------------------------------------------------------- /fetch_cord/computer/resources.py: -------------------------------------------------------------------------------- 1 | #from __future__ import annotations 2 | 3 | 4 | try: 5 | import importlib.resources as pkg_resources 6 | except ImportError: 7 | # Try backported to PY<37 `importlib_resources`. 8 | import importlib_resources as pkg_resources 9 | import json 10 | 11 | from .. import resources as fc_resources 12 | 13 | 14 | def get_infos(): 15 | with pkg_resources.open_text(fc_resources, "fetchcord_ids.json") as f: 16 | infos = json.load(f) 17 | 18 | return infos 19 | 20 | 21 | def get_default_config(): 22 | with pkg_resources.path(fc_resources, "default.conf") as path: 23 | return path 24 | 25 | return None 26 | -------------------------------------------------------------------------------- /fetch_cord/config.py: -------------------------------------------------------------------------------- 1 | #from __future__ import annotations 2 | 3 | 4 | try: 5 | import importlib.resources as pkg_resources 6 | except ImportError: 7 | # Try backported to PY<37 `importlib_resources`. 8 | import importlib_resources as pkg_resources 9 | import os, copy, json, configparser 10 | 11 | from . import resources as fc_resources 12 | from .args import parse_args 13 | 14 | 15 | args = parse_args() 16 | 17 | 18 | class ConfigError(Exception): 19 | pass 20 | 21 | 22 | def load_config(): 23 | default_config = configparser.ConfigParser() 24 | with pkg_resources.path(fc_resources, "fetch_cord.conf") as path: 25 | default_config.read_file(open(path)) 26 | default_config.read( 27 | ["/etc/fetch_cord.conf", os.path.expanduser("~/fetch_cord.conf")] 28 | ) 29 | if args.fetchcord_config_path != None: 30 | default_config.read([args.fetchcord_config_path]) 31 | for item in default_config.items(): 32 | print(item) 33 | 34 | default_config = _parsed_config_to_dict(default_config) 35 | _validate_config(default_config) 36 | 37 | return default_config 38 | 39 | 40 | # def load_config(): 41 | # base_config = configparser.ConfigParser() 42 | # base_config.read(["/etc/fetch_cord.conf"]) 43 | # base_config = _parsed_config_to_dict(base_config) 44 | # _validate_config(base_config) 45 | 46 | 47 | # # try: 48 | # user_config = configparser.ConfigParser() 49 | # user_config.read("/etc/fetch_cord.conf") 50 | # user_config = _parsed_config_to_dict(user_config) 51 | # # except configparser.ParsingError as e: 52 | # # print( 53 | # # "Error parsing config file %s. Falling back to default config %s. Error is : %s", 54 | # # envs.USER_CONFIG_COPY_PATH, envs.DEFAULT_CONFIG_PATH, str(e)) 55 | # return base_config 56 | 57 | # corrected_config = _validate_config(user_config, fallback_config=base_config) 58 | 59 | 60 | # return corrected_config 61 | 62 | 63 | def _validate_config(config, fallback_config=None): 64 | 65 | folder_path = os.path.dirname(os.path.abspath(__file__)) 66 | schema_path = os.path.join(folder_path, "config_schema.json") 67 | 68 | with open(schema_path, "r") as f: 69 | schema = json.load(f) 70 | 71 | corrected_config = copy.deepcopy(config) 72 | 73 | # Checking if the config file has the required sections and options 74 | for section in schema.keys(): 75 | 76 | if section not in config.keys(): 77 | raise ConfigError("Cannot find header for section [%s]" % section) 78 | 79 | for option in schema[section].keys(): 80 | 81 | if option not in config[section].keys(): 82 | raise ConfigError( 83 | 'Cannot find option "%s" in section [%s]' % (option, section) 84 | ) 85 | 86 | valid, msg = _validate_option( 87 | schema[section][option], config[section][option] 88 | ) 89 | 90 | if not valid: 91 | error_msg = ( 92 | 'Config parsing : error in option "%s" in section [%s] : %s' 93 | % (option, section, msg) 94 | ) 95 | if fallback_config is not None: 96 | print(error_msg) 97 | print( 98 | 'Falling back to default value "%s"', 99 | fallback_config[section][option], 100 | ) 101 | corrected_config[section][option] = fallback_config[section][option] 102 | 103 | else: 104 | raise ConfigError(error_msg) 105 | 106 | # Checking if the config file has no unknown section or option 107 | for section in config.keys(): 108 | 109 | if section not in schema.keys(): 110 | print("Config parsing : unknown section [%s]. Ignoring.", section) 111 | continue 112 | 113 | for option in config[section].keys(): 114 | if option not in schema[section].keys(): 115 | print( 116 | 'Config parsing : unknown option "%s" in section [%s]. Ignoring.', 117 | option, 118 | section, 119 | ) 120 | del corrected_config[section][option] 121 | 122 | return corrected_config 123 | 124 | 125 | def _parsed_config_to_dict(config): 126 | 127 | config_dict = {} 128 | 129 | for section in config.keys(): 130 | 131 | if section == "DEFAULT": 132 | continue 133 | 134 | config_dict[section] = {} 135 | 136 | for option in config[section].keys(): 137 | config_dict[section][option] = config[section][option] 138 | 139 | return config_dict 140 | 141 | 142 | def _validate_option(schema_option_info, config_option_value): 143 | valid = False 144 | msg = "error" 145 | 146 | parameter_type = schema_option_info[0] 147 | 148 | assert parameter_type in ["multi_words", "single_word", "integer"] 149 | 150 | # Multiple-words parameters 151 | if parameter_type == "multi_words": 152 | valid, msg = _validate_multi_words(schema_option_info, config_option_value) 153 | 154 | # Single-word parameters 155 | elif parameter_type == "single_word": 156 | valid, msg = _validate_single_word(schema_option_info, config_option_value) 157 | 158 | # Integer parameter 159 | elif parameter_type == "integer": 160 | valid, msg = _validate_integer(schema_option_info, config_option_value) 161 | 162 | return valid, msg 163 | 164 | 165 | def _validate_multi_words(schema_option_info, config_option_value): 166 | 167 | parameter_type, allowed_values, can_be_blank = schema_option_info 168 | assert parameter_type == "multi_words" 169 | 170 | values = config_option_value.replace(" ", "").split(",") 171 | 172 | if values == [""]: 173 | if not can_be_blank: 174 | msg = "at least one parameter required" 175 | return False, msg 176 | 177 | else: 178 | for val in values: 179 | if val not in allowed_values: 180 | msg = 'invalid value "%s"' % val 181 | return False, msg 182 | 183 | return True, None 184 | 185 | 186 | def _validate_single_word(schema_option_info, config_option_value): 187 | 188 | parameter_type, allowed_values, can_be_blank = schema_option_info 189 | assert parameter_type == "single_word" 190 | 191 | val = config_option_value.replace(" ", "") 192 | 193 | if val == "": 194 | if not can_be_blank: 195 | msg = "non-blank value required" 196 | return False, msg 197 | 198 | else: 199 | if val not in allowed_values: 200 | msg = 'invalid value "%s"' % val 201 | return False, msg 202 | 203 | return True, None 204 | 205 | 206 | def _validate_integer(schema_option_info, config_option_value): 207 | 208 | parameter_type, can_be_blank = schema_option_info 209 | assert parameter_type == "integer" 210 | 211 | val = config_option_value.replace(" ", "") 212 | 213 | if val == "": 214 | if not can_be_blank: 215 | msg = "non-blank integer value required" 216 | return False, msg 217 | 218 | else: 219 | try: 220 | v = int(val) 221 | if v <= 0: 222 | raise ValueError 223 | except ValueError: 224 | msg = "non-blank integer value required" 225 | return False, msg 226 | 227 | return True, None 228 | -------------------------------------------------------------------------------- /fetch_cord/config_schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "cycle_0": 3 | { 4 | "top_line": ["single_word", ["kernel", "packages"], false], 5 | "bottom_line": ["single_word", ["kernel", "packages"], false], 6 | "de_wm_icon": ["single_word", ["on", "off"], true], 7 | "time": ["single_word", ["15", "30", "45", "60", "75", "90", "105", "120", "240", "480"], false] 8 | }, 9 | 10 | "cycle_1": 11 | { 12 | "top_line": ["single_word", ["cpu", "gpu", "mem", "disk"], false], 13 | "bottom_line": ["single_word", ["cpu", "gpu", "mem", "disk"], false], 14 | "gpu_icon": ["single_word", ["on", "off"], true], 15 | "time": ["single_word", ["15", "30", "45", "60", "75", "90", "105", "120", "240", "480"], false] 16 | }, 17 | 18 | "cycle_2": 19 | { 20 | "top_line": ["single_word", ["font", "shell", "theme"], false], 21 | "bottom_line": ["single_word", ["font", "shell", "theme"], false], 22 | "shell_icon": ["single_word", ["on", "off"], true], 23 | "time": ["single_word", ["15", "30", "45", "60", "75", "90", "105", "120", "240", "480"], false] 24 | }, 25 | 26 | "cycle_3": 27 | { 28 | "top_line": ["single_word", ["resolution", "battery", "host"], false], 29 | "bottom_line": ["single_word", ["resolution", "battery", "host"], false], 30 | "lapordesk_icon": ["single_word", ["on", "off"], true], 31 | "time": ["single_word", ["15", "30", "45", "60", "75", "90", "105", "120", "240", "480"], false] 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /fetch_cord/cycles.py: -------------------------------------------------------------------------------- 1 | #from __future__ import annotations 2 | 3 | import time 4 | from typing import Dict 5 | 6 | from .computer.Computer import Computer 7 | from .run_rpc import Run_rpc 8 | from .args import parse_args 9 | 10 | args = parse_args() 11 | 12 | 13 | class Cycles: 14 | config: Dict[str, str] 15 | 16 | def __init__(self, config: Dict[str, str]): 17 | self.config = config 18 | 19 | 20 | def pause(run: Run_rpc, key: str, computer: Computer): 21 | if args.debug: 22 | print("pause_cycle") 23 | if args.time: 24 | time.sleep(int(args.time)) 25 | else: 26 | time.sleep(30) 27 | 28 | 29 | def windows(run: Run_rpc, key: str, computer: Computer): 30 | if args.debug: 31 | print("w_cycle 0") 32 | 33 | run.try_update( 34 | key, 35 | state=computer.osinfo, 36 | details=computer.memory, 37 | large_image="big", 38 | large_text=computer.osinfo, 39 | small_image=computer.motherboardid, 40 | small_text=computer.motherboard, 41 | start=computer.uptime, 42 | ) 43 | 44 | if args.time: 45 | time.sleep(int(args.time)) 46 | elif args.nohardware: 47 | time.sleep(9999) 48 | else: 49 | time.sleep(30) 50 | run.try_clear(key) 51 | 52 | 53 | def runmac(run: Run_rpc, key: str, computer: Computer): 54 | if args.debug: 55 | print("runmac") 56 | print("devicetype: %s" % computer.devicetype) 57 | print("product %s" % computer.product) 58 | print("bigicon: %s" % computer.bigicon) 59 | print("ver: %s" % computer.version) 60 | print("uptime: %s" % computer.uptime) 61 | 62 | run.try_update( 63 | key, 64 | state=computer.packages, # update state as packages 65 | details=computer.kernel, # update details as kernel 66 | large_image=computer.bigicon, # set icon 67 | large_text=computer.osinfo, # set large icon text 68 | small_image=computer.devicetype, # set small image icon 69 | small_text=computer.product, # set small image text 70 | start=computer.uptime, 71 | ) 72 | if args.time: 73 | time.sleep(int(args.time)) 74 | elif args.nohost and args.nohardware and args.noshell: 75 | time.sleep(9999) 76 | else: 77 | time.sleep(30) 78 | run.try_clear(key) 79 | 80 | 81 | def cycle0(run: Run_rpc, key: str, computer: Computer): 82 | top_line = run.config["cycle_0"]["top_line"] 83 | if top_line == "kernel": 84 | top_line = computer.kernel 85 | else: 86 | top_line = computer.packages 87 | bottom_line = run.config["cycle_0"]["bottom_line"] 88 | if bottom_line == "kernel": 89 | bottom_line = computer.kernel 90 | else: 91 | bottom_line = computer.packages 92 | de_wm_icon = run.config["cycle_0"]["de_wm_icon"] 93 | if de_wm_icon == "on": 94 | de_wm_icon = computer.desktopid 95 | else: 96 | de_wm_icon = "off" 97 | if args.debug: 98 | print("cycle 0") 99 | 100 | run.try_update( 101 | key, 102 | state=bottom_line, 103 | details=top_line, 104 | large_image="big", 105 | large_text=computer.osinfo, 106 | small_image=de_wm_icon, 107 | small_text=computer.dewmid, 108 | start=computer.uptime, 109 | ) 110 | if args.debug: 111 | print("appid: %s" % computer.osinfoid) 112 | config_time = run.config["cycle_0"]["time"] 113 | if args.time: 114 | time.sleep(int(args.time)) 115 | elif args.nohost and args.nohardware and args.noshell: 116 | time.sleep(9999) 117 | elif config_time: 118 | time.sleep(int(config_time)) 119 | else: 120 | time.sleep(30) 121 | run.try_clear(key) 122 | 123 | 124 | def cycle1(run: Run_rpc, key: str, computer: Computer): 125 | top_line = run.config["cycle_1"]["top_line"] 126 | if top_line == "gpu": 127 | top_line = computer.gpu 128 | elif top_line == "cpu": 129 | top_line = computer.cpu 130 | elif top_line == "mem": 131 | top_line = computer.memory 132 | elif top_line == "disk": 133 | top_line = computer.disks 134 | bottom_line = run.config["cycle_1"]["bottom_line"] 135 | if bottom_line == "gpu": 136 | bottom_line = computer.gpu 137 | elif bottom_line == "cpu": 138 | bottom_line = computer.cpu 139 | elif bottom_line == "mem": 140 | bottom_line = computer.memory 141 | elif bottom_line == "disk": 142 | bottom_line = computer.disks 143 | gpu_icon = run.config["cycle_1"]["gpu_icon"] 144 | if gpu_icon == "on": 145 | gpu_icon = computer.gpuid 146 | else: 147 | gpu_icon = "off" 148 | if args.debug: 149 | print("cycle 1") 150 | run.try_update( 151 | key, 152 | state=bottom_line, 153 | details=top_line, 154 | large_image="big", 155 | large_text=computer.cpu, 156 | small_image=gpu_icon, 157 | small_text=computer.gpu, 158 | start=computer.uptime, 159 | ) 160 | if args.debug: 161 | print("appid: %s" % computer.cpuid) 162 | config_time = run.config["cycle_1"]["time"] 163 | if args.time: 164 | time.sleep(int(args.time)) 165 | elif args.nodistro and args.noshell and args.nohost: 166 | time.sleep(9999) 167 | elif config_time: 168 | time.sleep(int(config_time)) 169 | else: 170 | time.sleep(30) 171 | run.try_clear(key) 172 | 173 | 174 | def cycle2(run: Run_rpc, key: str, computer: Computer): 175 | top_line = run.config["cycle_2"]["top_line"] 176 | if top_line == "font": 177 | top_line = computer.terminal 178 | elif top_line == "shell": 179 | top_line = computer.shellid 180 | elif top_line == "theme": 181 | top_line = computer.theme 182 | bottom_line = run.config["cycle_2"]["bottom_line"] 183 | if bottom_line == "font": 184 | bottom_line = computer.terminal 185 | elif bottom_line == "shell": 186 | bottom_line = computer.shell 187 | elif bottom_line == "theme": 188 | bottom_line = computer.theme 189 | shell_icon = run.config["cycle_2"]["shell_icon"] 190 | if shell_icon == "on": 191 | shell_icon = computer.shellid 192 | else: 193 | shell_icon = "off" 194 | if args.debug: 195 | print("cycle 2") 196 | 197 | run.try_update( 198 | key, 199 | state=bottom_line, 200 | details=top_line, 201 | large_image="big", 202 | large_text=computer.terminal, 203 | small_image=shell_icon, 204 | small_text=computer.shell, 205 | start=computer.uptime, 206 | ) 207 | if args.debug: 208 | print("appid: %s" % computer.osinfoid) 209 | 210 | config_time = run.config["cycle_2"]["time"] 211 | 212 | if args.time: 213 | time.sleep(int(args.time)) 214 | elif args.nodistro and args.nohardware and args.nohost: 215 | time.sleep(9999) 216 | elif config_time: 217 | time.sleep(int(config_time)) 218 | else: 219 | time.sleep(30) 220 | run.try_clear(key) 221 | 222 | 223 | def cycle3(run: Run_rpc, key: str, computer: Computer): 224 | # if not then forget it 225 | if computer.host != "Host: N/A" and computer.motherboard != "Motherboard: N/A": 226 | top_line = run.config["cycle_3"]["top_line"] 227 | if top_line == "battery": 228 | top_line = computer.battery 229 | elif top_line == "host": 230 | top_line = computer.motherboard 231 | elif top_line == "resolution": 232 | top_line = computer.resolution 233 | bottom_line = run.config["cycle_3"]["bottom_line"] 234 | if bottom_line == "resolution": 235 | bottom_line = computer.resolution 236 | elif bottom_line == "host": 237 | bottom_line = computer.motherboard 238 | elif bottom_line == "battery": 239 | bottom_line = computer.battery 240 | lapordesk_icon = run.config["cycle_3"]["lapordesk_icon"] 241 | if lapordesk_icon == "on": 242 | lapordesk_icon = computer.lapordesk 243 | else: 244 | lapordesk_icon = "off" 245 | if args.debug: 246 | print("cycle 3") 247 | run.try_update( 248 | key, 249 | state=computer.resolution, 250 | details=computer.battery, 251 | large_image="big", 252 | large_text=computer.motherboard, 253 | small_image=lapordesk_icon, 254 | small_text=computer.lapordesk, 255 | start=computer.uptime, 256 | ) 257 | if args.debug: 258 | print("appid: %s" % computer.hostappid) 259 | config_time = run.config["cycle_3"]["time"] 260 | if args.time: 261 | time.sleep(int(args.time)) 262 | elif args.nodistro and args.nohardware and args.noshell: 263 | time.sleep(9999) 264 | elif config_time: 265 | time.sleep(int(config_time)) 266 | else: 267 | time.sleep(30) 268 | # back from whence you came 269 | run.try_clear(key) 270 | -------------------------------------------------------------------------------- /fetch_cord/debugger.py: -------------------------------------------------------------------------------- 1 | # from __future__ import annotations 2 | 3 | from typing import List 4 | 5 | from .computer.Computer import Computer 6 | from .computer.cpu.Cpu_interface import Cpu_interface 7 | 8 | 9 | def run_debug(computer: Computer): 10 | print("----out.py----\n") 11 | print("----DE/WM----") 12 | if not computer.neofetchwin: 13 | print("deid: %s" % computer.deid) 14 | print("wmid: %s" % computer.wmid) 15 | try: 16 | print("wmline item 0: %s" % computer.wm) 17 | except IndexError: 18 | pass 19 | print("\n----TERMINAL----\n") 20 | print("fontline: %s" % computer.font) 21 | print("termid: %s" % computer.terminalid) 22 | print("termline item 0: %s" % computer.terminal) 23 | print("themeline: %s" % computer.theme) 24 | if computer.host != "Host: N/A": 25 | print("\n----HOST INFO----\n") 26 | print("hostline: %s" % computer.host) 27 | if computer.battery != computer.host: 28 | print("batteryline: %s" % computer.battery) 29 | print("resline: %s" % computer.resolution) 30 | print("\n----GPU INFO----\n") 31 | print("gpuinfo: %s" % computer.gpu) 32 | print("gpuvendor: %s" % computer.gpuid) 33 | print("\n----CPU INFO----\n") 34 | cpu: List[Cpu_interface] = computer.get_component("CPU:") 35 | if cpu: 36 | print("cpuvendor: %s" % cpu[0].vendor) 37 | print("cpumodel: %s" % cpu[0].model) 38 | print("cpuinfo: %s" % cpu[0].info) 39 | print("cpuline item 0: %s" % computer.cpu) 40 | print("memline: %s" % computer.memory) 41 | print("\n----OS INFO----\n") 42 | print("sysosline: %s" % computer.osinfo) 43 | print("sysosid: %s" % computer.osinfoid) 44 | print("diskline: %s" % computer.disks) 45 | if computer.os != "windows": 46 | print("packagesline item 0: %s" % computer.packages) 47 | 48 | 49 | def test_debug(computer: Computer): 50 | print("\n----testing.py----") 51 | if computer.os != "windows": 52 | print("----DE/WM----\n") 53 | print("deid: %s" % computer.deid) 54 | print("wmid: %s" % computer.wmid) 55 | print("\n----TERMINAL/SHELL----\n") 56 | print("termid: %s" % computer.terminalid) 57 | print("shellid: %s" % computer.shellid) 58 | print("\n----HOST INFO----\n") 59 | print("hostid: %s" % computer.hostid) 60 | else: 61 | print("moboid: %s" % computer.motherboardid) 62 | print("moboline: %s" % computer.motherboard) 63 | print("\n----GPU INFO----\n") 64 | print("gpuvendor: %s" % computer.gpuid) 65 | print("\n----CPU INFO----\n") 66 | cpu = computer.get_component("CPU:") 67 | if cpu: 68 | print("cpumodel: %s\n" % cpu[0].model) 69 | 70 | 71 | def run_rpc_debug(computer: Computer): 72 | print("----run_rpc----\n") 73 | print("uptime in epoch: %s" % computer.uptime) 74 | print("cpuid: %s" % computer.osinfoid) 75 | print("cpuappid: %s" % computer.cpuid) 76 | if computer.os != "windows": 77 | print("termappid: %s" % computer.terminalid) 78 | if computer.host != "Host: N/A": 79 | print("hostappid: %s" % computer.hostappid) 80 | print(computer.packages) 81 | 82 | run_debug(computer) 83 | test_debug(computer) -------------------------------------------------------------------------------- /fetch_cord/resources/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fetchcord/FetchCord/3833c0f1464fb5703e712db4ebf0e7f88f22a829/fetch_cord/resources/__init__.py -------------------------------------------------------------------------------- /fetch_cord/resources/default.conf: -------------------------------------------------------------------------------- 1 | # See this wiki page for more info: 2 | # https://github.com/dylanaraps/neofetch/wiki/Customizing-Info 3 | print_info() { 4 | info title 5 | info underline 6 | 7 | info "OS" distro 8 | info "Host" model 9 | info "Kernel" kernel 10 | info "Uptime" uptime 11 | info "Packages" packages 12 | info "Shell" shell 13 | info "Resolution" resolution 14 | info "DE" de 15 | info "WM" wm 16 | info "WM Theme" wm_theme 17 | info "Theme" theme 18 | info "Icons" icons 19 | info "Terminal" term 20 | info "Terminal Font" term_font 21 | info "CPU" cpu 22 | info "GPU" gpu 23 | info "Memory" memory 24 | info "Battery" battery 25 | info "Disk" disk 26 | 27 | # info "GPU Driver" gpu_driver # Linux/macOS only 28 | # info "CPU Usage" cpu_usage 29 | # info "Disk" disk 30 | # info "Battery" battery 31 | # info "Font" font 32 | # info "Song" song 33 | # [[ "$player" ]] && prin "Music Player" "$player" 34 | # info "Local IP" local_ip 35 | # info "Public IP" public_ip 36 | # info "Users" users 37 | # info "Locale" locale # This only works on glibc systems. 38 | 39 | info cols 40 | } 41 | 42 | # Title 43 | 44 | 45 | # Hide/Show Fully qualified domain name. 46 | # 47 | # Default: 'off' 48 | # Values: 'on', 'off' 49 | # Flag: --title_fqdn 50 | title_fqdn="off" 51 | 52 | 53 | # Kernel 54 | 55 | 56 | # Shorten the output of the kernel function. 57 | # 58 | # Default: 'on' 59 | # Values: 'on', 'off' 60 | # Flag: --kernel_shorthand 61 | # Supports: Everything except *BSDs (except PacBSD and PC-BSD) 62 | # 63 | # Example: 64 | # on: '4.8.9-1-ARCH' 65 | # off: 'Linux 4.8.9-1-ARCH' 66 | kernel_shorthand="on" 67 | 68 | 69 | # Distro 70 | 71 | 72 | # Shorten the output of the distro function 73 | # 74 | # Default: 'off' 75 | # Values: 'on', 'tiny', 'off' 76 | # Flag: --distro_shorthand 77 | # Supports: Everything except Windows and Haiku 78 | distro_shorthand="off" 79 | 80 | # Show/Hide OS Architecture. 81 | # Show 'x86_64', 'x86' and etc in 'Distro:' output. 82 | # 83 | # Default: 'on' 84 | # Values: 'on', 'off' 85 | # Flag: --os_arch 86 | # 87 | # Example: 88 | # on: 'Arch Linux x86_64' 89 | # off: 'Arch Linux' 90 | os_arch="on" 91 | 92 | 93 | # Uptime 94 | 95 | 96 | # Shorten the output of the uptime function 97 | # 98 | # Default: 'on' 99 | # Values: 'on', 'tiny', 'off' 100 | # Flag: --uptime_shorthand 101 | # 102 | # Example: 103 | # on: '2 days, 10 hours, 3 mins' 104 | # tiny: '2d 10h 3m' 105 | # off: '2 days, 10 hours, 3 minutes' 106 | uptime_shorthand="on" 107 | 108 | 109 | # Memory 110 | 111 | 112 | # Show memory pecentage in output. 113 | # 114 | # Default: 'off' 115 | # Values: 'on', 'off' 116 | # Flag: --memory_percent 117 | # 118 | # Example: 119 | # on: '1801MiB / 7881MiB (22%)' 120 | # off: '1801MiB / 7881MiB' 121 | memory_percent="off" 122 | 123 | 124 | # Packages 125 | 126 | 127 | # Show/Hide Package Manager names. 128 | # 129 | # Default: 'tiny' 130 | # Values: 'on', 'tiny' 'off' 131 | # Flag: --package_managers 132 | # 133 | # Example: 134 | # on: '998 (pacman), 8 (flatpak), 4 (snap)' 135 | # tiny: '908 (pacman, flatpak, snap)' 136 | # off: '908' 137 | package_managers="on" 138 | 139 | 140 | # Shell 141 | 142 | 143 | # Show the path to $SHELL 144 | # 145 | # Default: 'off' 146 | # Values: 'on', 'off' 147 | # Flag: --shell_path 148 | # 149 | # Example: 150 | # on: '/bin/bash' 151 | # off: 'bash' 152 | shell_path="off" 153 | 154 | # Show $SHELL version 155 | # 156 | # Default: 'on' 157 | # Values: 'on', 'off' 158 | # Flag: --shell_version 159 | # 160 | # Example: 161 | # on: 'bash 4.4.5' 162 | # off: 'bash' 163 | shell_version="on" 164 | 165 | 166 | # CPU 167 | 168 | 169 | # CPU speed type 170 | # 171 | # Default: 'bios_limit' 172 | # Values: 'scaling_cur_freq', 'scaling_min_freq', 'scaling_max_freq', 'bios_limit'. 173 | # Flag: --speed_type 174 | # Supports: Linux with 'cpufreq' 175 | # NOTE: Any file in '/sys/devices/system/cpu/cpu0/cpufreq' can be used as a value. 176 | speed_type="bios_limit" 177 | 178 | # CPU speed shorthand 179 | # 180 | # Default: 'off' 181 | # Values: 'on', 'off'. 182 | # Flag: --speed_shorthand 183 | # NOTE: This flag is not supported in systems with CPU speed less than 1 GHz 184 | # 185 | # Example: 186 | # on: 'i7-6500U (4) @ 3.1GHz' 187 | # off: 'i7-6500U (4) @ 3.100GHz' 188 | speed_shorthand="off" 189 | 190 | # Enable/Disable CPU brand in output. 191 | # 192 | # Default: 'on' 193 | # Values: 'on', 'off' 194 | # Flag: --cpu_brand 195 | # 196 | # Example: 197 | # on: 'Intel i7-6500U' 198 | # off: 'i7-6500U (4)' 199 | cpu_brand="on" 200 | 201 | # CPU Speed 202 | # Hide/Show CPU speed. 203 | # 204 | # Default: 'on' 205 | # Values: 'on', 'off' 206 | # Flag: --cpu_speed 207 | # 208 | # Example: 209 | # on: 'Intel i7-6500U (4) @ 3.1GHz' 210 | # off: 'Intel i7-6500U (4)' 211 | cpu_speed="on" 212 | 213 | # CPU Cores 214 | # Display CPU cores in output 215 | # 216 | # Default: 'logical' 217 | # Values: 'logical', 'physical', 'off' 218 | # Flag: --cpu_cores 219 | # Support: 'physical' doesn't work on BSD. 220 | # 221 | # Example: 222 | # logical: 'Intel i7-6500U (4) @ 3.1GHz' (All virtual cores) 223 | # physical: 'Intel i7-6500U (2) @ 3.1GHz' (All physical cores) 224 | # off: 'Intel i7-6500U @ 3.1GHz' 225 | cpu_cores="logical" 226 | 227 | # CPU Temperature 228 | # Hide/Show CPU temperature. 229 | # Note the temperature is added to the regular CPU function. 230 | # 231 | # Default: 'off' 232 | # Values: 'C', 'F', 'off' 233 | # Flag: --cpu_temp 234 | # Supports: Linux, BSD 235 | # NOTE: For FreeBSD and NetBSD-based systems, you'll need to enable 236 | # coretemp kernel module. This only supports newer Intel processors. 237 | # 238 | # Example: 239 | # C: 'Intel i7-6500U (4) @ 3.1GHz [27.2°C]' 240 | # F: 'Intel i7-6500U (4) @ 3.1GHz [82.0°F]' 241 | # off: 'Intel i7-6500U (4) @ 3.1GHz' 242 | cpu_temp="off" 243 | 244 | 245 | # GPU 246 | 247 | 248 | # Enable/Disable GPU Brand 249 | # 250 | # Default: 'on' 251 | # Values: 'on', 'off' 252 | # Flag: --gpu_brand 253 | # 254 | # Example: 255 | # on: 'AMD HD 7950' 256 | # off: 'HD 7950' 257 | gpu_brand="on" 258 | 259 | # Which GPU to display 260 | # 261 | # Default: 'all' 262 | # Values: 'all', 'dedicated', 'integrated' 263 | # Flag: --gpu_type 264 | # Supports: Linux 265 | # 266 | # Example: 267 | # all: 268 | # GPU1: AMD HD 7950 269 | # GPU2: Intel Integrated Graphics 270 | # 271 | # dedicated: 272 | # GPU1: AMD HD 7950 273 | # 274 | # integrated: 275 | # GPU1: Intel Integrated Graphics 276 | gpu_type="all" 277 | 278 | 279 | # Resolution 280 | 281 | 282 | # Display refresh rate next to each monitor 283 | # Default: 'off' 284 | # Values: 'on', 'off' 285 | # Flag: --refresh_rate 286 | # Supports: Doesn't work on Windows. 287 | # 288 | # Example: 289 | # on: '1920x1080 @ 60Hz' 290 | # off: '1920x1080' 291 | refresh_rate="off" 292 | 293 | 294 | # Gtk Theme / Icons / Font 295 | 296 | 297 | # Shorten output of GTK Theme / Icons / Font 298 | # 299 | # Default: 'off' 300 | # Values: 'on', 'off' 301 | # Flag: --gtk_shorthand 302 | # 303 | # Example: 304 | # on: 'Numix, Adwaita' 305 | # off: 'Numix [GTK2], Adwaita [GTK3]' 306 | gtk_shorthand="off" 307 | 308 | 309 | # Enable/Disable gtk2 Theme / Icons / Font 310 | # 311 | # Default: 'on' 312 | # Values: 'on', 'off' 313 | # Flag: --gtk2 314 | # 315 | # Example: 316 | # on: 'Numix [GTK2], Adwaita [GTK3]' 317 | # off: 'Adwaita [GTK3]' 318 | gtk2="on" 319 | 320 | # Enable/Disable gtk3 Theme / Icons / Font 321 | # 322 | # Default: 'on' 323 | # Values: 'on', 'off' 324 | # Flag: --gtk3 325 | # 326 | # Example: 327 | # on: 'Numix [GTK2], Adwaita [GTK3]' 328 | # off: 'Numix [GTK2]' 329 | gtk3="on" 330 | 331 | 332 | # IP Address 333 | 334 | 335 | # Website to ping for the public IP 336 | # 337 | # Default: 'http://ident.me' 338 | # Values: 'url' 339 | # Flag: --ip_host 340 | public_ip_host="http://ident.me" 341 | 342 | # Public IP timeout. 343 | # 344 | # Default: '2' 345 | # Values: 'int' 346 | # Flag: --ip_timeout 347 | public_ip_timeout=2 348 | 349 | 350 | # Desktop Environment 351 | 352 | 353 | # Show Desktop Environment version 354 | # 355 | # Default: 'off' 356 | # Values: 'on', 'off' 357 | # Flag: --de_version 358 | de_version="on" 359 | 360 | 361 | # Disk 362 | 363 | 364 | # Which disks to display. 365 | # The values can be any /dev/sdXX, mount point or directory. 366 | # NOTE: By default we only show the disk info for '/'. 367 | # 368 | # Default: '/' 369 | # Values: '/', '/dev/sdXX', '/path/to/drive'. 370 | # Flag: --disk_show 371 | # 372 | # Example: 373 | # disk_show=('/' '/dev/sdb1'): 374 | # 'Disk (/): 74G / 118G (66%)' 375 | # 'Disk (/mnt/Videos): 823G / 893G (93%)' 376 | # 377 | # disk_show=('/'): 378 | # 'Disk (/): 74G / 118G (66%)' 379 | # 380 | disk_show=('/') 381 | 382 | # Disk subtitle. 383 | # What to append to the Disk subtitle. 384 | # 385 | # Default: 'mount' 386 | # Values: 'mount', 'name', 'dir', 'none' 387 | # Flag: --disk_subtitle 388 | # 389 | # Example: 390 | # name: 'Disk (/dev/sda1): 74G / 118G (66%)' 391 | # 'Disk (/dev/sdb2): 74G / 118G (66%)' 392 | # 393 | # mount: 'Disk (/): 74G / 118G (66%)' 394 | # 'Disk (/mnt/Local Disk): 74G / 118G (66%)' 395 | # 'Disk (/mnt/Videos): 74G / 118G (66%)' 396 | # 397 | # dir: 'Disk (/): 74G / 118G (66%)' 398 | # 'Disk (Local Disk): 74G / 118G (66%)' 399 | # 'Disk (Videos): 74G / 118G (66%)' 400 | # 401 | # none: 'Disk: 74G / 118G (66%)' 402 | # 'Disk: 74G / 118G (66%)' 403 | # 'Disk: 74G / 118G (66%)' 404 | disk_subtitle="mount" 405 | 406 | # Disk percent. 407 | # Show/Hide disk percent. 408 | # 409 | # Default: 'on' 410 | # Values: 'on', 'off' 411 | # Flag: --disk_percent 412 | # 413 | # Example: 414 | # on: 'Disk (/): 74G / 118G (66%)' 415 | # off: 'Disk (/): 74G / 118G' 416 | disk_percent="on" 417 | 418 | 419 | # Song 420 | 421 | 422 | # Manually specify a music player. 423 | # 424 | # Default: 'auto' 425 | # Values: 'auto', 'player-name' 426 | # Flag: --music_player 427 | # 428 | # Available values for 'player-name': 429 | # 430 | # amarok 431 | # audacious 432 | # banshee 433 | # bluemindo 434 | # clementine 435 | # cmus 436 | # deadbeef 437 | # deepin-music 438 | # dragon 439 | # elisa 440 | # exaile 441 | # gnome-music 442 | # gmusicbrowser 443 | # gogglesmm 444 | # guayadeque 445 | # io.elementary.music 446 | # iTunes 447 | # juk 448 | # lollypop 449 | # mocp 450 | # mopidy 451 | # mpd 452 | # muine 453 | # netease-cloud-music 454 | # pogo 455 | # pragha 456 | # qmmp 457 | # quodlibet 458 | # rhythmbox 459 | # sayonara 460 | # smplayer 461 | # spotify 462 | # strawberry 463 | # tomahawk 464 | # vlc 465 | # xmms2d 466 | # xnoise 467 | # yarock 468 | music_player="auto" 469 | 470 | # Format to display song information. 471 | # 472 | # Default: '%artist% - %album% - %title%' 473 | # Values: '%artist%', '%album%', '%title%' 474 | # Flag: --song_format 475 | # 476 | # Example: 477 | # default: 'Song: Jet - Get Born - Sgt Major' 478 | song_format="%artist% - %album% - %title%" 479 | 480 | # Print the Artist, Album and Title on separate lines 481 | # 482 | # Default: 'off' 483 | # Values: 'on', 'off' 484 | # Flag: --song_shorthand 485 | # 486 | # Example: 487 | # on: 'Artist: The Fratellis' 488 | # 'Album: Costello Music' 489 | # 'Song: Chelsea Dagger' 490 | # 491 | # off: 'Song: The Fratellis - Costello Music - Chelsea Dagger' 492 | song_shorthand="off" 493 | 494 | # 'mpc' arguments (specify a host, password etc). 495 | # 496 | # Default: '' 497 | # Example: mpc_args=(-h HOST -P PASSWORD) 498 | mpc_args=() 499 | 500 | 501 | # Text Colors 502 | 503 | 504 | # Text Colors 505 | # 506 | # Default: 'distro' 507 | # Values: 'distro', 'num' 'num' 'num' 'num' 'num' 'num' 508 | # Flag: --colors 509 | # 510 | # Each number represents a different part of the text in 511 | # this order: 'title', '@', 'underline', 'subtitle', 'colon', 'info' 512 | # 513 | # Example: 514 | # colors=(distro) - Text is colored based on Distro colors. 515 | # colors=(4 6 1 8 8 6) - Text is colored in the order above. 516 | colors=(distro) 517 | 518 | 519 | # Text Options 520 | 521 | 522 | # Toggle bold text 523 | # 524 | # Default: 'on' 525 | # Values: 'on', 'off' 526 | # Flag: --bold 527 | bold="on" 528 | 529 | # Enable/Disable Underline 530 | # 531 | # Default: 'on' 532 | # Values: 'on', 'off' 533 | # Flag: --underline 534 | underline_enabled="on" 535 | 536 | # Underline character 537 | # 538 | # Default: '-' 539 | # Values: 'string' 540 | # Flag: --underline_char 541 | underline_char="-" 542 | 543 | 544 | # Info Separator 545 | # Replace the default separator with the specified string. 546 | # 547 | # Default: ':' 548 | # Flag: --separator 549 | # 550 | # Example: 551 | # separator="->": 'Shell-> bash' 552 | # separator=" =": 'WM = dwm' 553 | separator=":" 554 | 555 | 556 | # Color Blocks 557 | 558 | 559 | # Color block range 560 | # The range of colors to print. 561 | # 562 | # Default: '0', '15' 563 | # Values: 'num' 564 | # Flag: --block_range 565 | # 566 | # Example: 567 | # 568 | # Display colors 0-7 in the blocks. (8 colors) 569 | # neofetch --block_range 0 7 570 | # 571 | # Display colors 0-15 in the blocks. (16 colors) 572 | # neofetch --block_range 0 15 573 | block_range=(0 15) 574 | 575 | # Toggle color blocks 576 | # 577 | # Default: 'on' 578 | # Values: 'on', 'off' 579 | # Flag: --color_blocks 580 | color_blocks="on" 581 | 582 | # Color block width in spaces 583 | # 584 | # Default: '3' 585 | # Values: 'num' 586 | # Flag: --block_width 587 | block_width=3 588 | 589 | # Color block height in lines 590 | # 591 | # Default: '1' 592 | # Values: 'num' 593 | # Flag: --block_height 594 | block_height=1 595 | 596 | # Color Alignment 597 | # 598 | # Default: 'auto' 599 | # Values: 'auto', 'num' 600 | # Flag: --col_offset 601 | # 602 | # Number specifies how far from the left side of the terminal (in spaces) to 603 | # begin printing the columns, in case you want to e.g. center them under your 604 | # text. 605 | # Example: 606 | # col_offset="auto" - Default behavior of neofetch 607 | # col_offset=7 - Leave 7 spaces then print the colors 608 | col_offset="auto" 609 | 610 | # Progress Bars 611 | 612 | 613 | # Bar characters 614 | # 615 | # Default: '-', '=' 616 | # Values: 'string', 'string' 617 | # Flag: --bar_char 618 | # 619 | # Example: 620 | # neofetch --bar_char 'elapsed' 'total' 621 | # neofetch --bar_char '-' '=' 622 | bar_char_elapsed="-" 623 | bar_char_total="=" 624 | 625 | # Toggle Bar border 626 | # 627 | # Default: 'on' 628 | # Values: 'on', 'off' 629 | # Flag: --bar_border 630 | bar_border="on" 631 | 632 | # Progress bar length in spaces 633 | # Number of chars long to make the progress bars. 634 | # 635 | # Default: '15' 636 | # Values: 'num' 637 | # Flag: --bar_length 638 | bar_length=15 639 | 640 | # Progress bar colors 641 | # When set to distro, uses your distro's logo colors. 642 | # 643 | # Default: 'distro', 'distro' 644 | # Values: 'distro', 'num' 645 | # Flag: --bar_colors 646 | # 647 | # Example: 648 | # neofetch --bar_colors 3 4 649 | # neofetch --bar_colors distro 5 650 | bar_color_elapsed="distro" 651 | bar_color_total="distro" 652 | 653 | 654 | # Info display 655 | # Display a bar with the info. 656 | # 657 | # Default: 'off' 658 | # Values: 'bar', 'infobar', 'barinfo', 'off' 659 | # Flags: --cpu_display 660 | # --memory_display 661 | # --battery_display 662 | # --disk_display 663 | # 664 | # Example: 665 | # bar: '[---=======]' 666 | # infobar: 'info [---=======]' 667 | # barinfo: '[---=======] info' 668 | # off: 'info' 669 | cpu_display="off" 670 | memory_display="off" 671 | battery_display="off" 672 | disk_display="off" 673 | 674 | 675 | # Backend Settings 676 | 677 | 678 | # Image backend. 679 | # 680 | # Default: 'ascii' 681 | # Values: 'ascii', 'caca', 'chafa', 'jp2a', 'iterm2', 'off', 682 | # 'termpix', 'pixterm', 'tycat', 'w3m', 'kitty' 683 | # Flag: --backend 684 | image_backend="ascii" 685 | 686 | # Image Source 687 | # 688 | # Which image or ascii file to display. 689 | # 690 | # Default: 'auto' 691 | # Values: 'auto', 'ascii', 'wallpaper', '/path/to/img', '/path/to/ascii', '/path/to/dir/' 692 | # 'command output (neofetch --ascii "$(fortune | cowsay -W 30)")' 693 | # Flag: --source 694 | # 695 | # NOTE: 'auto' will pick the best image source for whatever image backend is used. 696 | # In ascii mode, distro ascii art will be used and in an image mode, your 697 | # wallpaper will be used. 698 | image_source="auto" 699 | 700 | 701 | # Ascii Options 702 | 703 | 704 | # Ascii distro 705 | # Which distro's ascii art to display. 706 | # 707 | # Default: 'auto' 708 | # Values: 'auto', 'distro_name' 709 | # Flag: --ascii_distro 710 | # NOTE: AIX, Alpine, Anarchy, Android, Antergos, antiX, AOSC, 711 | # Apricity, ArcoLinux, ArchBox, ARCHlabs, ArchStrike, 712 | # XFerience, ArchMerge, Arch, Artix, Arya, Bedrock, Bitrig, 713 | # BlackArch, BLAG, BlankOn, BlueLight, bonsai, BSD, 714 | # BunsenLabs, Calculate, Carbs, CentOS, Chakra, ChaletOS, 715 | # Chapeau, Chrom*, Cleanjaro, ClearOS, Clear_Linux, Clover, 716 | # Condres, Container_Linux, CRUX, Cucumber, Debian, Deepin, 717 | # DesaOS, Devuan, DracOS, DragonFly, Drauger, Elementary, 718 | # EndeavourOS, Endless, EuroLinux, Exherbo, Fedora, Feren, FreeBSD, 719 | # FreeMiNT, Frugalware, Funtoo, GalliumOS, Gentoo, Pentoo, 720 | # gNewSense, GNU, GoboLinux, Grombyang, Guix, Haiku, Huayra, 721 | # Hyperbola, janus, Kali, KaOS, KDE_neon, Kibojoe, Kogaion, 722 | # Korora, KSLinux, Kubuntu, LEDE, LFS, Linux_Lite, 723 | # LMDE, Lubuntu, Lunar, macos, Mageia, MagpieOS, Mandriva, 724 | # Manjaro, Maui, Mer, Minix, LinuxMint, MX_Linux, Namib, 725 | # Neptune, NetBSD, Netrunner, Nitrux, NixOS, Nurunner, 726 | # NuTyX, OBRevenge, OpenBSD, OpenIndiana, OpenMandriva, 727 | # OpenWrt, osmc, Oracle, PacBSD, Parabola, Pardus, Parrot, 728 | # Parsix, TrueOS, PCLinuxOS, Peppermint, popos, Porteus, 729 | # PostMarketOS, Proxmox, Puppy, PureOS, Qubes, Radix, Raspbian, 730 | # Reborn_OS, Redstar, Redcore, Redhat, Refracted_Devuan, Regata, 731 | # Rosa, sabotage, Sabayon, Sailfish, SalentOS, Scientific, Septor, 732 | # SharkLinux, Siduction, Slackware, SliTaz, SmartOS, Solus, 733 | # Source_Mage, Sparky, Star, SteamOS, SunOS, openSUSE_Leap, 734 | # openSUSE_Tumbleweed, openSUSE, SwagArch, Tails, Trisquel, 735 | # Ubuntu-Budgie, Ubuntu-GNOME, Ubuntu-MATE, Ubuntu-Studio, Ubuntu, 736 | # Void, Obarun, windows10, Windows7, Xubuntu, Zorin, and IRIX 737 | # have ascii logos 738 | # NOTE: Arch, Ubuntu, Redhat, and Dragonfly have 'old' logo variants. 739 | # Use '{distro name}_old' to use the old logos. 740 | # NOTE: Ubuntu has flavor variants. 741 | # Change this to Lubuntu, Kubuntu, Xubuntu, Ubuntu-GNOME, 742 | # Ubuntu-Studio, Ubuntu-Mate or Ubuntu-Budgie to use the flavors. 743 | # NOTE: Arcolinux, Dragonfly, Fedora, Alpine, Arch, Ubuntu, 744 | # CRUX, Debian, Gentoo, FreeBSD, Mac, NixOS, OpenBSD, android, 745 | # Antrix, CentOS, Cleanjaro, ElementaryOS, GUIX, Hyperbola, 746 | # Manjaro, MXLinux, NetBSD, Parabola, POP_OS, PureOS, 747 | # Slackware, SunOS, LinuxLite, OpenSUSE, Raspbian, 748 | # postmarketOS, and Void have a smaller logo variant. 749 | # Use '{distro name}_small' to use the small variants. 750 | ascii_distro="auto" 751 | 752 | # Ascii Colors 753 | # 754 | # Default: 'distro' 755 | # Values: 'distro', 'num' 'num' 'num' 'num' 'num' 'num' 756 | # Flag: --ascii_colors 757 | # 758 | # Example: 759 | # ascii_colors=(distro) - Ascii is colored based on Distro colors. 760 | # ascii_colors=(4 6 1 8 8 6) - Ascii is colored using these colors. 761 | ascii_colors=(distro) 762 | 763 | # Bold ascii logo 764 | # Whether or not to bold the ascii logo. 765 | # 766 | # Default: 'on' 767 | # Values: 'on', 'off' 768 | # Flag: --ascii_bold 769 | ascii_bold="on" 770 | 771 | 772 | # Image Options 773 | 774 | 775 | # Image loop 776 | # Setting this to on will make neofetch redraw the image constantly until 777 | # Ctrl+C is pressed. This fixes display issues in some terminal emulators. 778 | # 779 | # Default: 'off' 780 | # Values: 'on', 'off' 781 | # Flag: --loop 782 | image_loop="off" 783 | 784 | # Thumbnail directory 785 | # 786 | # Default: '~/.cache/thumbnails/neofetch' 787 | # Values: 'dir' 788 | thumbnail_dir="${XDG_CACHE_HOME:-${HOME}/.cache}/thumbnails/neofetch" 789 | 790 | # Crop mode 791 | # 792 | # Default: 'normal' 793 | # Values: 'normal', 'fit', 'fill' 794 | # Flag: --crop_mode 795 | # 796 | # See this wiki page to learn about the fit and fill options. 797 | # https://github.com/dylanaraps/neofetch/wiki/What-is-Waifu-Crop%3F 798 | crop_mode="normal" 799 | 800 | # Crop offset 801 | # Note: Only affects 'normal' crop mode. 802 | # 803 | # Default: 'center' 804 | # Values: 'northwest', 'north', 'northeast', 'west', 'center' 805 | # 'east', 'southwest', 'south', 'southeast' 806 | # Flag: --crop_offset 807 | crop_offset="center" 808 | 809 | # Image size 810 | # The image is half the terminal width by default. 811 | # 812 | # Default: 'auto' 813 | # Values: 'auto', '00px', '00%', 'none' 814 | # Flags: --image_size 815 | # --size 816 | image_size="auto" 817 | 818 | # Gap between image and text 819 | # 820 | # Default: '3' 821 | # Values: 'num', '-num' 822 | # Flag: --gap 823 | gap=3 824 | 825 | # Image offsets 826 | # Only works with the w3m backend. 827 | # 828 | # Default: '0' 829 | # Values: 'px' 830 | # Flags: --xoffset 831 | # --yoffset 832 | yoffset=0 833 | xoffset=0 834 | 835 | # Image background color 836 | # Only works with the w3m backend. 837 | # 838 | # Default: '' 839 | # Values: 'color', 'blue' 840 | # Flag: --bg_color 841 | background_color= 842 | 843 | 844 | # Misc Options 845 | 846 | # Stdout mode 847 | # Turn off all colors and disables image backend (ASCII/Image). 848 | # Useful for piping into another command. 849 | # Default: 'off' 850 | # Values: 'on', 'off' 851 | stdout="off" 852 | -------------------------------------------------------------------------------- /fetch_cord/resources/fetch_cord.conf: -------------------------------------------------------------------------------- 1 | [cycle_0] 2 | 3 | # Order to set info in discord presence, valid values are: kernel, packages 4 | top_line=kernel 5 | bottom_line=packages 6 | # show small_icon in Discord 7 | de_wm_icon=on 8 | 9 | # Duration to show this cycle 10 | # valid values are, 15, 30, 45, 60, 75, 90, 105, 120, 240, and 480 11 | time=30 12 | 13 | [cycle_1] 14 | 15 | # Order to set info in discord presence, valid values are: mem, gpu, cpu, and disk 16 | top_line=mem 17 | bottom_line=gpu 18 | # show small_icon in Discord 19 | gpu_icon=on 20 | 21 | # Duration to show this cycle 22 | # valid values are, 15, 30, 45, 60, 75, 90, 105, 120, 240, and 480 23 | time=30 24 | 25 | [cycle_2] 26 | 27 | # Order to set info in discord presence, valid values are: font, shell, and theme 28 | top_line=font 29 | bottom_line=shell 30 | # show small_icon in Discord 31 | shell_icon=on 32 | 33 | # Duration to show this cycle 34 | # valid values are, 15, 30, 45, 60, 75, 90, 105, 120, 240, and 480 35 | time=30 36 | 37 | [cycle_3] 38 | 39 | # Order to set info in discord presence, valid values are: battery, resolution, and host 40 | top_line=battery 41 | bottom_line=resolution 42 | # show small_icon in Discord 43 | lapordesk_icon=on 44 | 45 | # Duration to show this cycle 46 | # valid values are, 15, 30, 45, 60, 75, 90, 105, 120, 240, and 480 47 | time=30 -------------------------------------------------------------------------------- /fetch_cord/resources/fetchcord_ids.json: -------------------------------------------------------------------------------- 1 | { 2 | "map": { 3 | "GPU:": "gpu", 4 | "CPU:": "cpu", 5 | "Terminal:": "terminal", 6 | "Motherboard:": "motherboard", 7 | "Host:": "motherboard", 8 | "Shell:": "shell", 9 | "OS:": "distro", 10 | "DE:": "desktop", 11 | "WM:": "windowmanager", 12 | "Version:": "version" 13 | }, 14 | "gpu": { 15 | "amd": "amd", 16 | "radeon": "amd", 17 | "amdnvidia": "nvidiaamd", 18 | "amdintel": "amdintel", 19 | "nvidia": "nvidia", 20 | "nvidiaamd": "nvidiaamd", 21 | "nvidiaintel": "nvidiaintel", 22 | "intel": "intel", 23 | "intelamd": "amdintel", 24 | "intelnvidia": "nvidiaintel", 25 | "vmware": "vmware", 26 | "virtio": "virtio", 27 | "cirrus": "cirrus", 28 | "unknown": "off" 29 | }, 30 | "cpu": { 31 | "amd": { 32 | "ryzen 3": "741153175779803146", 33 | "ryzen 5": "741152732756312125", 34 | "ryzen 7": "740752899054895105", 35 | "ryzen 9": "741152930899427364", 36 | "ryzen threadripper": "742075019257184338", 37 | "a4 apu": "820717165329645618", 38 | "a6 apu": "820711517715693608", 39 | "a8 apu": "820715505437638708", 40 | "a9 apu": "820738634473930752", 41 | "a10 apu": "820726638635122740", 42 | "a12 apu": "820737378494054451", 43 | "fx apu": "820739431711113226", 44 | "athlon silver": "870365152401293452", 45 | "athlon gold": "870365152401293452" 46 | }, 47 | "intel": { 48 | "intel i3": "741044208512532570", 49 | "intel i5": "741099939198926920", 50 | "intel i7": "741100300219187335", 51 | "intel i9": "741100622040006719", 52 | "intel pentium": "741203845706940467", 53 | "intel celeron": "742904581360713849", 54 | "pentium": "741203845706940467", 55 | "intel core 2 duo": "746527640382603375", 56 | "intel2 duo": "746527640382603375", 57 | "intel core 2 quad": "785615606438166544", 58 | "intel2 quad": "785615606438166544", 59 | "intel xeon": "749011141090607144" 60 | }, 61 | "unknown": "742887089179197462" 62 | }, 63 | "terminal": { 64 | "st": "741280043220861030", 65 | "kitty": "741285676250824725", 66 | "alacritty": "741291339945345045", 67 | "xterm": "741287143187546125", 68 | "konsole": "741286819676553258", 69 | "dolphin": "741286819676553258", 70 | "gnome-terminal": "741328861115056160", 71 | "cool-retro-term": "741731097498353794", 72 | "urxvt": "743246048968835092", 73 | "xfce4-terminal": "744332423072055296", 74 | "apple_terminal": "744950796298354689", 75 | "lxterminal": "745701997503840380", 76 | "yakuake": "741286819676553258", 77 | "mate-terminal": "746531413360377856", 78 | "terminus": "878027718132899901", 79 | "io.elementary.t": "878027718132899901", 80 | "windows terminal": "878034077444374559", 81 | "unknown": "745691250186911796" 82 | }, 83 | "motherboard": { 84 | "asrock": "811349714946490408", 85 | "aorus": "749061181607772200", 86 | "inspiron": "743970870631858288", 87 | "latitude": "743970870631858288", 88 | "g3": "743970870631858288", 89 | "hp": "743971270395297852", 90 | "hewlett-packard": "743971270395297852", 91 | "J7D10ET": "743971270395297852", 92 | "tuf": "744330890343219262", 93 | "asus": "743936082780880928", 94 | "asustek": "743936082780880928", 95 | "acer": "744326890512318544", 96 | "KBL (Metapod_KL)": "744326890512318544", 97 | "thinkpad": "744326223412461630", 98 | "ideapad": "744326223412461630", 99 | "lenovo": "744326223412461630", 100 | "thinkcentre": "744326223412461630", 101 | "gigabyte": "746447043190456561", 102 | "Z370XP SLI": "746447043190456561", 103 | "Z390 GAMING X": "746447043190456561", 104 | "macbookair,": "748290608787095694", 105 | "macbookpro,": "750016315854553138", 106 | "aspire": "744326890512318544", 107 | "DL (Tulip_DA)": "744326890512318544", 108 | "hvm": "749014556604497972", 109 | "dell": "785620748021792788", 110 | "msi": "787106184783200266", 111 | "optiplex 780": "785620748021792788", 112 | "optiplex": "785620748021792788", 113 | "H310M A 2.0": "746447043190456561", 114 | "K53TA 1.0": "743936082780880928", 115 | "MS-7C02 1.0": "787106184783200266", 116 | "PE70 6QD REV:1.0": "787106184783200266", 117 | "unknown": "742887089179197462" 118 | }, 119 | "shell": { 120 | "fish": "fish", 121 | "zsh": "zsh", 122 | "bash": "bash", 123 | "tcsh": "tcsh", 124 | "ruby": "ruby", 125 | "unknown": "unknown" 126 | }, 127 | "distro": { 128 | "elementary": "877994542912114718", 129 | "ubuntu": "740434138036699178", 130 | "opensuseleap": "740156532137787433", 131 | "arch": "740476198437650473", 132 | "arco": "745435867971321866", 133 | "artix": "741918141248045107", 134 | "fedora": "740485660703719464", 135 | "void": "740484961353597039", 136 | "gentoo/linux": "740484380652208140", 137 | "funtoo": "740484380652208140", 138 | "centos": "740483295388631071", 139 | "debian": "740490017218232392", 140 | "opensusetumbleweed": "742180413132505088", 141 | "manjaro": "740614258177605642", 142 | "linuxmint": "740633577481568317", 143 | "lmde": "741726946588622988", 144 | "pop!_os": "740660055925587978", 145 | "endeavouros": "740809641545564170", 146 | "windows10": "741949889465942099", 147 | "windows7": "741952383512346696", 148 | "windows8": "741952179488948324", 149 | "windows8.1": "741952065294827520", 150 | "windows11": "865716441431932959", 151 | "nixos": "744644133494325329", 152 | "instantos": "744784599653285938", 153 | "freebsd": "745054697047457822", 154 | "solus": "745689115944681683", 155 | "zorin": "745689865798156379", 156 | "amazon": "749014983920320583", 157 | "bedrock": "749015250904416287", 158 | "garuda": "820649067695833118", 159 | "parrotos": "852597254509297684", 160 | "rebornos": "852619769551257650", 161 | "mageia": "852639226445299752", 162 | "unknown": "742993278143692821" 163 | }, 164 | "desktop": { 165 | "kde": "kde", 166 | "plasma": "plasma", 167 | "xfce": "xfce", 168 | "budgie": "budgie", 169 | "gnome": "gnome", 170 | "deepin": "deepin", 171 | "cinnamon": "cinnamon", 172 | "mate": "mate", 173 | "aero": "aero", 174 | "pantheon": "pantheon", 175 | "explorer": "explorer", 176 | "unknown": "unknown" 177 | }, 178 | "windowmanager": { 179 | "dwm": "dwm", 180 | "i3": "i3", 181 | "awesome": "awesome", 182 | "enlightenment": "enlightenment", 183 | "bspwm": "bspwm", 184 | "xmonad": "xmonad", 185 | "sway": "sway", 186 | "openbox": "openbox", 187 | "herbstluftwm": "herbstluftwm", 188 | "unknown": "unknown" 189 | }, 190 | "version": { 191 | "10.13": "hsierria", 192 | "10.14": "mojave", 193 | "10.15": "catalina", 194 | "unknown": "unknown" 195 | } 196 | } -------------------------------------------------------------------------------- /fetch_cord/resources/systemd_service.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | from os import system 4 | from ..run_command import BashError, exec_bash 5 | from ..args import parse_args 6 | import sys 7 | 8 | args = parse_args() 9 | 10 | 11 | def systemd_cmd(cmd: str): 12 | try: 13 | print(exec_bash(f"systemctl --user {cmd} --now fetchcord")) 14 | except BashError as err: 15 | print(err) 16 | sys.exit(1) 17 | 18 | 19 | def install(): 20 | try: 21 | exec_bash("mkdir -p ~/.local/share/systemd/user") 22 | except: 23 | print("Error : Cannot create directory...") 24 | sys.exit(1) 25 | 26 | try: 27 | exec_bash( 28 | f"wget -O ~/.local/share/systemd/user/fetchcord.service https://raw.githubusercontent.com/MrPotatoBobx/FetchCord/{'testing' if args.testing else 'master'}/systemd/fetchcord.service", 29 | ) 30 | except: 31 | print("Error: Failed to download the service file.") 32 | sys.exit(1) 33 | 34 | systemd_cmd("enable") 35 | 36 | start() 37 | 38 | 39 | def uninstall(): 40 | systemd_cmd("stop") 41 | 42 | systemd_cmd("disable") 43 | 44 | try: 45 | exec_bash("rm -f ~/.local/share/systemd/user/fetchcord.service") 46 | except: 47 | print("Error : Cannot remove service file...") 48 | sys.exit(1) 49 | 50 | sys.exit(0) 51 | 52 | 53 | def enable(): 54 | systemd_cmd("enable") 55 | sys.exit(0) 56 | 57 | 58 | def disable(): 59 | systemd_cmd("disable") 60 | sys.exit(0) 61 | 62 | 63 | def start(): 64 | systemd_cmd("start") 65 | sys.exit(0) 66 | 67 | 68 | def stop(): 69 | systemd_cmd("stop") 70 | sys.exit(0) 71 | 72 | 73 | def status(): 74 | systemd_cmd("status") 75 | sys.exit(0) -------------------------------------------------------------------------------- /fetch_cord/run_command.py: -------------------------------------------------------------------------------- 1 | #from __future__ import annotations 2 | 3 | from typing import List 4 | import subprocess 5 | 6 | 7 | def run_command(command: List[str], shell: bool = False): 8 | return subprocess.run( 9 | command, encoding="utf-8", stdout=subprocess.PIPE, shell=shell 10 | ).stdout 11 | 12 | 13 | class BashError(Exception): 14 | pass 15 | 16 | 17 | def exec_bash(command: str): 18 | try: 19 | out = ( 20 | subprocess.check_output(["bash", "-c", command], stderr=subprocess.STDOUT) 21 | .decode("utf8") 22 | .strip() 23 | ) 24 | 25 | except subprocess.CalledProcessError as e: 26 | out = e.stdout.decode("utf8") 27 | raise BashError("Failed to execute '%s' :\n%s" % (command, out)) 28 | except FileNotFoundError as e: 29 | raise BashError("BASH not installed on your computer...") 30 | 31 | return out 32 | -------------------------------------------------------------------------------- /fetch_cord/run_rpc.py: -------------------------------------------------------------------------------- 1 | #from __future__ import annotations 2 | 3 | 4 | from typing import Callable, Dict 5 | from pypresence import Presence, exceptions 6 | import time, sys 7 | 8 | # import info about system 9 | from .args import parse_args 10 | from .config import ConfigError, load_config 11 | from .computer.Computer import Computer 12 | 13 | args = parse_args() 14 | 15 | 16 | class Run_rpc: 17 | rpcs: Dict[str, Presence] 18 | config: Dict 19 | 20 | loops: Dict[str, Callable[['Run_rpc', str, Computer], None]] # Cannot use Run_rpc for type hinting unless doing the __future__.annotations import 21 | loops_indexes: Dict[int, str] 22 | poll_rate: int 23 | update: Callable 24 | 25 | def __init__(self): 26 | self.rpcs = {} 27 | 28 | try: 29 | self.config = load_config() 30 | except ConfigError as e: 31 | print("Error loading config file, using default values." % str(e)) 32 | 33 | def set_loop( 34 | self, loops: Dict, loops_indexes: Dict, update: Callable, poll_rate: int = 3 35 | ): 36 | self.loops = loops 37 | self.loops_indexes = loops_indexes 38 | 39 | self.poll_rate = poll_rate 40 | self.update = update 41 | 42 | def run_loop(self, computer: Computer): 43 | try: 44 | loop = 0 45 | while True: 46 | for i in range(len(self.loops_indexes)): 47 | if loop == self.poll_rate: 48 | self.update() 49 | loop = 0 50 | try: 51 | client_id, func = self.loops[self.loops_indexes[i]] 52 | 53 | if args.debug: 54 | print(self.rpcs) 55 | print( 56 | "{} not in : {}".format( 57 | self.loops_indexes[i], 58 | self.loops_indexes[i] not in self.rpcs, 59 | ) 60 | ) 61 | if self.loops_indexes[i] not in self.rpcs: 62 | self.rpcs[self.loops_indexes[i]] = Presence(client_id) 63 | self.try_connect(self.loops_indexes[i]) 64 | 65 | func(self, self.loops_indexes[i], computer) 66 | loop += 1 67 | except ConnectionResetError: 68 | self.try_connect(self.loops_indexes[i]) 69 | except KeyboardInterrupt: 70 | print("Closing connection.") 71 | sys.exit(0) 72 | 73 | def try_connect(self, key: str): 74 | while True: 75 | try: 76 | if args.debug: 77 | print('try_connect(key="{}") on {}'.format(key, self.rpcs[key])) 78 | self.rpcs[key].connect() 79 | break 80 | except ConnectionRefusedError: 81 | print( 82 | "RPC connection refused (is Discord open?); trying again in 30 seconds" 83 | ) 84 | time.sleep(30) 85 | 86 | def try_clear(self, key: str): 87 | # Pypresence clear doesn't work anymore 88 | # try: 89 | # if args.debug: 90 | # print( 91 | # "[key={}] try_clear(pid={} on {}".format( 92 | # key, os.getpid(), self.rpcs[key] 93 | # ) 94 | # ) 95 | # self.rpcs[key].clear(pid=os.getpid()) 96 | # except exceptions.InvalidID: 97 | # pass 98 | # except exceptions.ServerError as e: 99 | # print(e) 100 | # pass 101 | self.rpcs[key].close() 102 | 103 | def try_update( 104 | self, 105 | key: str, 106 | state, 107 | details, 108 | large_image, 109 | large_text, 110 | small_image, 111 | small_text, 112 | start, 113 | ): 114 | try: 115 | if args.debug: 116 | print('try_update(key="{}") on {}'.format(key, self.rpcs[key])) 117 | self.rpcs[key].update( 118 | state=state, 119 | details=details, 120 | large_image=large_image, 121 | large_text=large_text, 122 | small_image=small_image, 123 | small_text=small_text, 124 | start=start, 125 | ) 126 | # ConnectionResetError is here to avoid crashing if Discord is still just starting 127 | except (ConnectionResetError, exceptions.InvalidID): 128 | pass -------------------------------------------------------------------------------- /fetch_cord/update.py: -------------------------------------------------------------------------------- 1 | #from __future__ import annotations 2 | 3 | import urllib.request, sys, os 4 | from .args import parse_args 5 | 6 | args = parse_args() 7 | 8 | def update(): 9 | print("Updating database...") 10 | url = f"https://raw.githubusercontent.com/MrPotatoBobx/FetchCord/{'testing' if args.testing else 'master'}/fetch_cord/resources/fetchcord_ids.json" 11 | urllib.request.urlretrieve( 12 | url, os.path.dirname(__file__) + "/resources/fetchcord_ids.json" 13 | ) 14 | sys.exit(0) 15 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | from os.path import dirname, join 3 | import setuptools 4 | import fetch_cord.__init__ as __init__ 5 | 6 | setuptools.setup( 7 | name="FetchCord", 8 | version=__init__.VERSION, 9 | description="grabs information about your Distro and displays it as Discord Rich Presence.", 10 | long_description=open(join(dirname(__file__), "README.md")).read(), 11 | long_description_content_type="text/markdown", 12 | url="https://github.com/MrPotatoBobx/FetchCord", 13 | author="MrPotatoBobx", 14 | author_email="junkahole23@protonmail.com", 15 | license="MIT", 16 | package_data={ 17 | "fetch_cord": [ 18 | "config_schema.json", 19 | "resources/default.conf", 20 | "resources/fetch_cord.conf", 21 | "resources/fetchcord_ids.json", 22 | "computer/*.py", 23 | "computer/*/*.py", 24 | ] 25 | }, 26 | packages=["fetch_cord"], 27 | include_package_data=True, 28 | install_requires=["pypresence", "psutil", "importlib-resources"], 29 | keywords=["distro", "info", "discord", "fetch"], 30 | classifiers=[ 31 | "License :: OSI Approved :: MIT License", 32 | "Programming Language :: Python :: 3", 33 | "Operating System :: OS Independent", 34 | ], 35 | python_requires=">=3.6", 36 | entry_points={ 37 | "console_scripts": [ 38 | "fetchcord=fetch_cord.__main__:main", 39 | ] 40 | }, 41 | ) 42 | -------------------------------------------------------------------------------- /snapcraft.yaml: -------------------------------------------------------------------------------- 1 | name: fetchcord 2 | version: git # By specifying git for the version, the current git tag or commit will be used as the version string. Versions carry no semantic meaning in snaps. This can be changed to a normal version number if desired. 3 | summary: FetchCord 4 | grade: stable 5 | description: | 6 | FetchCord grabs your OS info and displays it as Discord Rich Presence 7 | base: core18 8 | confinement: classic 9 | 10 | parts: 11 | fetchcord: 12 | plugin: python 13 | python-version: python3 14 | source: . 15 | stage-packages: 16 | - neofetch 17 | python-packages: 18 | - pypresence 19 | - psutil 20 | - importlib-resources 21 | 22 | apps: 23 | fetchcord: 24 | command: bin/fetchcord -------------------------------------------------------------------------------- /systemd/fetchcord.service: -------------------------------------------------------------------------------- 1 | # Please use 'systemctl --user edit fetchcord' to change 'ExecStart' when adding arguments! 2 | # The following is a simple example of the override: 3 | 4 | # [Service] 5 | # ExecStart= 6 | # ExecStart=-/usr/bin/fetchcord --nohost --time 15 --terminal 'gnome-terminal' --termfont 'Terminus Medium' 7 | 8 | [Unit] 9 | Description=Display OS info as Discord Rich Presence 10 | Documentation=https://github.com/MrPotatoBobx/FetchCord 11 | After=network.target multi-user.target graphical-session.target 12 | 13 | [Service] 14 | Environment=PYTHONUNBUFFERED=1 15 | ExecStart=-/usr/bin/env fetchcord 16 | Restart=always 17 | RestartSec=10 18 | 19 | [Install] 20 | WantedBy=default.target 21 | -------------------------------------------------------------------------------- /tests/test_fetch_cord_computer.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | 3 | from fetch_cord.computer.Computer import Computer 4 | 5 | 6 | def make_orderer(): 7 | order = {} 8 | 9 | def ordered(f): 10 | order[f.__name__] = len(order) 11 | return f 12 | 13 | def compare(a, b): 14 | return [1, -1][order[a] < order[b]] 15 | 16 | return ordered, compare 17 | 18 | 19 | ordered, compare = make_orderer() 20 | unittest.defaultTestLoader.sortTestMethodsUsing = compare 21 | 22 | 23 | class TestFetchCordComputer(unittest.TestCase): 24 | """Test class for Computer module""" 25 | 26 | pc: Computer 27 | 28 | @classmethod 29 | def setUpClass(cls): 30 | """Setup the Computer class and load the neofetch info""" 31 | 32 | cls.pc = Computer() 33 | 34 | @classmethod 35 | def tearDownClass(self): 36 | """Called once at the end""" 37 | pass 38 | 39 | @ordered 40 | def test_detected_os(self): 41 | """Test the detected os result""" 42 | 43 | print("Detected OS : " + self.pc.os) 44 | 45 | @ordered 46 | def test_detected_neofetch(self): 47 | """Test detected neofetch""" 48 | 49 | print("Detected Neofetch : ", end="") 50 | if self.pc.neofetch: 51 | print("neofetch") 52 | elif self.pc.neofetchwin: 53 | print("neofetch-win") 54 | else: 55 | print("None") 56 | 57 | @ordered 58 | def test_detected_cpu(self): 59 | """Test detected CPU""" 60 | 61 | if len(self.pc.cpu) == 0 or self.pc.cpu == ["N/A"]: 62 | print("No CPU detected !") 63 | else: 64 | for cpu in self.pc.cpu: 65 | print("Detected CPU : " + cpu.model) 66 | print("Detected CPU Temp : " + str(cpu.temp) + "°c") 67 | 68 | @ordered 69 | def test_detected_gpu(self): 70 | """Test detected GPU""" 71 | 72 | if len(self.pc.gpu) == 0 or self.pc.gpu == ["N/A"]: 73 | print("No GPU detected !") 74 | else: 75 | for gpu in self.pc.gpu: 76 | print("Detected GPU : " + gpu.model) 77 | 78 | @ordered 79 | def test_detected_disks(self): 80 | """Test detected disks""" 81 | 82 | if len(self.pc.disks) == 0 or self.pc.disks == ["N/A"]: 83 | print("No Disk detected !") 84 | else: 85 | for disk in self.pc.disks: 86 | print("Detected Disk : " + disk) 87 | 88 | @ordered 89 | def test_detected_memory(self): 90 | """Test detected memory""" 91 | 92 | print("Detected Memory : " + "\t".join(self.pc.memory)) 93 | 94 | @ordered 95 | def test_detected_osinfo(self): 96 | """Test detected OS info""" 97 | 98 | print("Detected OS info : " + "\t".join(self.pc.osinfo)) 99 | 100 | @ordered 101 | def test_detected_motherboard(self): 102 | """Test detected motherboard""" 103 | 104 | print("Detected Motherboard : " + "\t".join(self.pc.motherboard)) 105 | 106 | @ordered 107 | def test_detected_host(self): 108 | """Test detected host""" 109 | 110 | print("Detected host : " + "\t".join(self.pc.host)) 111 | 112 | @ordered 113 | def test_detected_resolution(self): 114 | """Test detected resolution""" 115 | 116 | print("Detected resolution : " + "\t".join(self.pc.resolution)) 117 | 118 | @ordered 119 | def test_detected_theme(self): 120 | """Test detected theme""" 121 | 122 | print("Detected theme : " + "\t".join(self.pc.theme)) 123 | 124 | @ordered 125 | def test_detected_packages(self): 126 | """Test detected packages""" 127 | 128 | print("Detected packages : " + "\t".join(self.pc.packages)) 129 | 130 | @ordered 131 | def test_detected_shell(self): 132 | """Test detected shell""" 133 | 134 | print("Detected shell : " + "\t".join(self.pc.shell)) 135 | 136 | @ordered 137 | def test_detected_kernel(self): 138 | """Test detected kernel""" 139 | 140 | print("Detected kernel : " + "\t".join(self.pc.kernel)) 141 | 142 | @ordered 143 | def test_detected_terminal(self): 144 | """Test detected terminal""" 145 | 146 | print("Detected terminal : " + "\t".join(self.pc.terminal)) 147 | 148 | @ordered 149 | def test_detected_font(self): 150 | """Test detected font""" 151 | 152 | print("Detected font : " + "\t".join(self.pc.font)) 153 | 154 | @ordered 155 | def test_detected_de(self): 156 | """Test detected de""" 157 | 158 | print("Detected de : " + "\t".join(self.pc.de)) 159 | 160 | @ordered 161 | def test_detected_wm(self): 162 | """Test detected wm""" 163 | 164 | print("Detected wm : " + "\t".join(self.pc.wm)) 165 | 166 | 167 | if __name__ == "__main__": 168 | unittest.main() 169 | --------------------------------------------------------------------------------