dripfetch 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dripfetch/__init__.py +1 -0
- dripfetch/__main__.py +4 -0
- dripfetch/app.py +111 -0
- dripfetch/assets/logos/adelie.txt +16 -0
- dripfetch/assets/logos/aeon.txt +14 -0
- dripfetch/assets/logos/aeros.txt +21 -0
- dripfetch/assets/logos/aerynos.txt +16 -0
- dripfetch/assets/logos/afterglow.txt +15 -0
- dripfetch/assets/logos/aix.txt +20 -0
- dripfetch/assets/logos/almalinux.txt +20 -0
- dripfetch/assets/logos/alpine.txt +20 -0
- dripfetch/assets/logos/alpine2.txt +16 -0
- dripfetch/assets/logos/alpine2_small.txt +6 -0
- dripfetch/assets/logos/alpine3_small.txt +6 -0
- dripfetch/assets/logos/alpine_small.txt +6 -0
- dripfetch/assets/logos/alter.txt +20 -0
- dripfetch/assets/logos/altlinux.txt +22 -0
- dripfetch/assets/logos/amazon.txt +19 -0
- dripfetch/assets/logos/amazon_linux.txt +10 -0
- dripfetch/assets/logos/amogos.txt +19 -0
- dripfetch/assets/logos/anarchy.txt +28 -0
- dripfetch/assets/logos/android.txt +18 -0
- dripfetch/assets/logos/android_small.txt +6 -0
- dripfetch/assets/logos/anduinos.txt +19 -0
- dripfetch/assets/logos/antergos.txt +19 -0
- dripfetch/assets/logos/antix.txt +12 -0
- dripfetch/assets/logos/anushos.txt +20 -0
- dripfetch/assets/logos/aoscos.txt +17 -0
- dripfetch/assets/logos/aoscos_old.txt +20 -0
- dripfetch/assets/logos/aoscosretro.txt +18 -0
- dripfetch/assets/logos/aoscosretro_small.txt +9 -0
- dripfetch/assets/logos/aperture.txt +20 -0
- dripfetch/assets/logos/apricity.txt +18 -0
- dripfetch/assets/logos/arch.txt +19 -0
- dripfetch/assets/logos/arch2.txt +19 -0
- dripfetch/assets/logos/arch3.txt +19 -0
- dripfetch/assets/logos/arch_old.txt +16 -0
- dripfetch/assets/logos/arch_small.txt +7 -0
- dripfetch/assets/logos/archbox.txt +19 -0
- dripfetch/assets/logos/archcraft.txt +20 -0
- dripfetch/assets/logos/archcraft2.txt +20 -0
- dripfetch/assets/logos/archlabs.txt +21 -0
- dripfetch/assets/logos/archstrike.txt +17 -0
- dripfetch/assets/logos/arco.txt +20 -0
- dripfetch/assets/logos/arco_small.txt +11 -0
- dripfetch/assets/logos/arkane.txt +23 -0
- dripfetch/assets/logos/armbian.txt +22 -0
- dripfetch/assets/logos/armbian2.txt +14 -0
- dripfetch/assets/logos/arselinux.txt +15 -0
- dripfetch/assets/logos/artix.txt +20 -0
- dripfetch/assets/logos/artix2_small.txt +13 -0
- dripfetch/assets/logos/artix_small.txt +7 -0
- dripfetch/assets/logos/arya.txt +15 -0
- dripfetch/assets/logos/asahi.txt +18 -0
- dripfetch/assets/logos/asahi2.txt +18 -0
- dripfetch/assets/logos/aster.txt +18 -0
- dripfetch/assets/logos/asteroidos.txt +17 -0
- dripfetch/assets/logos/astos.txt +23 -0
- dripfetch/assets/logos/astra_linux.txt +22 -0
- dripfetch/assets/logos/athenaos.txt +29 -0
- dripfetch/assets/logos/athenaos_old.txt +24 -0
- dripfetch/assets/logos/aurora.txt +28 -0
- dripfetch/assets/logos/axos.txt +16 -0
- dripfetch/assets/logos/azos.txt +17 -0
- dripfetch/assets/logos/bedrock.txt +17 -0
- dripfetch/assets/logos/bedrock_small.txt +6 -0
- dripfetch/assets/logos/biglinux.txt +19 -0
- dripfetch/assets/logos/bitrig.txt +17 -0
- dripfetch/assets/logos/blackarch.txt +21 -0
- dripfetch/assets/logos/blackmesa.txt +20 -0
- dripfetch/assets/logos/blackpanther.txt +23 -0
- dripfetch/assets/logos/blag.txt +17 -0
- dripfetch/assets/logos/blankon.txt +17 -0
- dripfetch/assets/logos/bluelight.txt +19 -0
- dripfetch/assets/logos/bodhi.txt +18 -0
- dripfetch/assets/logos/bonsai.txt +16 -0
- dripfetch/assets/logos/bredos.txt +9 -0
- dripfetch/assets/logos/bsd.txt +19 -0
- dripfetch/assets/logos/bunsenlabs.txt +20 -0
- dripfetch/assets/logos/cachyos.txt +22 -0
- dripfetch/assets/logos/cachyos_small.txt +8 -0
- dripfetch/assets/logos/calculate.txt +20 -0
- dripfetch/assets/logos/calinixos.txt +25 -0
- dripfetch/assets/logos/calinixos_small.txt +15 -0
- dripfetch/assets/logos/carbs.txt +18 -0
- dripfetch/assets/logos/cbl_mariner.txt +18 -0
- dripfetch/assets/logos/celos.txt +15 -0
- dripfetch/assets/logos/center.txt +13 -0
- dripfetch/assets/logos/centos.txt +19 -0
- dripfetch/assets/logos/centos_small.txt +7 -0
- dripfetch/assets/logos/cereus.txt +27 -0
- dripfetch/assets/logos/chakra.txt +18 -0
- dripfetch/assets/logos/chaletos.txt +20 -0
- dripfetch/assets/logos/chapeau.txt +18 -0
- dripfetch/assets/logos/chimera_linux.txt +18 -0
- dripfetch/assets/logos/chonkysealos.txt +21 -0
- dripfetch/assets/logos/chrom.txt +18 -0
- dripfetch/assets/logos/cleanjaro.txt +12 -0
- dripfetch/assets/logos/cleanjaro_small.txt +7 -0
- dripfetch/assets/logos/clear_linux.txt +20 -0
- dripfetch/assets/logos/clearos.txt +20 -0
- dripfetch/assets/logos/clover.txt +20 -0
- dripfetch/assets/logos/cobalt.txt +16 -0
- dripfetch/assets/logos/codex.txt +12 -0
- dripfetch/assets/logos/condres.txt +17 -0
- dripfetch/assets/logos/cosmic.txt +11 -0
- dripfetch/assets/logos/crux.txt +18 -0
- dripfetch/assets/logos/crux_small.txt +7 -0
- dripfetch/assets/logos/crystal.txt +20 -0
- dripfetch/assets/logos/cucumber.txt +20 -0
- dripfetch/assets/logos/cuerdos.txt +13 -0
- dripfetch/assets/logos/cutefishos.txt +9 -0
- dripfetch/assets/logos/cuteos.txt +14 -0
- dripfetch/assets/logos/cyberos.txt +15 -0
- dripfetch/assets/logos/cycledream.txt +21 -0
- dripfetch/assets/logos/dahlia.txt +17 -0
- dripfetch/assets/logos/darkos.txt +20 -0
- dripfetch/assets/logos/debian.txt +17 -0
- dripfetch/assets/logos/debian_small.txt +6 -0
- dripfetch/assets/logos/deepin.txt +18 -0
- dripfetch/assets/logos/desaos.txt +16 -0
- dripfetch/assets/logos/devuan.txt +15 -0
- dripfetch/assets/logos/devuan_small.txt +7 -0
- dripfetch/assets/logos/dietpi.txt +19 -0
- dripfetch/assets/logos/dracos.txt +13 -0
- dripfetch/assets/logos/dragonfly.txt +15 -0
- dripfetch/assets/logos/dragonfly_old.txt +17 -0
- dripfetch/assets/logos/dragonfly_small.txt +7 -0
- dripfetch/assets/logos/drauger.txt +16 -0
- dripfetch/assets/logos/droidian.txt +15 -0
- dripfetch/assets/logos/elbrus.txt +14 -0
- dripfetch/assets/logos/elementary.txt +17 -0
- dripfetch/assets/logos/elementary_small.txt +6 -0
- dripfetch/assets/logos/elive.txt +17 -0
- dripfetch/assets/logos/encryptos.txt +13 -0
- dripfetch/assets/logos/endeavouros.txt +15 -0
- dripfetch/assets/logos/endeavouros_small.txt +7 -0
- dripfetch/assets/logos/endless.txt +20 -0
- dripfetch/assets/logos/enso.txt +19 -0
- dripfetch/assets/logos/eshanizedos.txt +27 -0
- dripfetch/assets/logos/eurolinux.txt +18 -0
- dripfetch/assets/logos/evolutionos.txt +21 -0
- dripfetch/assets/logos/evolutionos_old.txt +18 -0
- dripfetch/assets/logos/evolutionos_small.txt +9 -0
- dripfetch/assets/logos/eweos.txt +15 -0
- dripfetch/assets/logos/exherbo.txt +22 -0
- dripfetch/assets/logos/exodia_predator.txt +24 -0
- dripfetch/assets/logos/fastfetch.txt +11 -0
- dripfetch/assets/logos/fedora.txt +19 -0
- dripfetch/assets/logos/fedora2_small.txt +5 -0
- dripfetch/assets/logos/fedora_coreos.txt +20 -0
- dripfetch/assets/logos/fedora_kinoite.txt +18 -0
- dripfetch/assets/logos/fedora_old.txt +17 -0
- dripfetch/assets/logos/fedora_sericea.txt +17 -0
- dripfetch/assets/logos/fedora_silverblue.txt +17 -0
- dripfetch/assets/logos/fedora_small.txt +9 -0
- dripfetch/assets/logos/femboyos.txt +20 -0
- dripfetch/assets/logos/feren.txt +16 -0
- dripfetch/assets/logos/filotimo.txt +20 -0
- dripfetch/assets/logos/finnix.txt +17 -0
- dripfetch/assets/logos/floflis.txt +19 -0
- dripfetch/assets/logos/freebsd.txt +15 -0
- dripfetch/assets/logos/freebsd_small.txt +6 -0
- dripfetch/assets/logos/freemint.txt +15 -0
- dripfetch/assets/logos/frugalware.txt +23 -0
- dripfetch/assets/logos/funtoo.txt +10 -0
- dripfetch/assets/logos/furreto.txt +22 -0
- dripfetch/assets/logos/galliumos.txt +19 -0
- dripfetch/assets/logos/garuda.txt +18 -0
- dripfetch/assets/logos/garuda_dragon.txt +24 -0
- dripfetch/assets/logos/garuda_small.txt +5 -0
- dripfetch/assets/logos/gentoo.txt +18 -0
- dripfetch/assets/logos/gentoo_small.txt +7 -0
- dripfetch/assets/logos/ghostbsd.txt +13 -0
- dripfetch/assets/logos/ghostfreak.txt +19 -0
- dripfetch/assets/logos/glaucus.txt +12 -0
- dripfetch/assets/logos/gnewsense.txt +12 -0
- dripfetch/assets/logos/gnome.txt +21 -0
- dripfetch/assets/logos/gnu.txt +18 -0
- dripfetch/assets/logos/gobolinux.txt +6 -0
- dripfetch/assets/logos/goldendoglinux.txt +19 -0
- dripfetch/assets/logos/grapheneos.txt +23 -0
- dripfetch/assets/logos/grombyang.txt +18 -0
- dripfetch/assets/logos/guix.txt +10 -0
- dripfetch/assets/logos/guix_small.txt +7 -0
- dripfetch/assets/logos/haiku.txt +12 -0
- dripfetch/assets/logos/haiku2.txt +17 -0
- dripfetch/assets/logos/haiku_small.txt +8 -0
- dripfetch/assets/logos/hamonikr.txt +23 -0
- dripfetch/assets/logos/hardclanz.txt +19 -0
- dripfetch/assets/logos/harmonyos.txt +19 -0
- dripfetch/assets/logos/hash.txt +13 -0
- dripfetch/assets/logos/hce.txt +24 -0
- dripfetch/assets/logos/heliumos.txt +20 -0
- dripfetch/assets/logos/huayra.txt +17 -0
- dripfetch/assets/logos/hybrid.txt +16 -0
- dripfetch/assets/logos/hydrapwk.txt +11 -0
- dripfetch/assets/logos/hydroos.txt +8 -0
- dripfetch/assets/logos/hyperbola.txt +16 -0
- dripfetch/assets/logos/hyperbola_small.txt +7 -0
- dripfetch/assets/logos/hypros.txt +17 -0
- dripfetch/assets/logos/iglunix.txt +12 -0
- dripfetch/assets/logos/instantos.txt +20 -0
- dripfetch/assets/logos/interix.txt +17 -0
- dripfetch/assets/logos/irix.txt +19 -0
- dripfetch/assets/logos/ironclad.txt +11 -0
- dripfetch/assets/logos/itc.txt +10 -0
- dripfetch/assets/logos/januslinux.txt +24 -0
- dripfetch/assets/logos/kaisen.txt +17 -0
- dripfetch/assets/logos/kali.txt +21 -0
- dripfetch/assets/logos/kali_small.txt +16 -0
- dripfetch/assets/logos/kalpa_desktop.txt +22 -0
- dripfetch/assets/logos/kaos.txt +16 -0
- dripfetch/assets/logos/kdelinux.txt +14 -0
- dripfetch/assets/logos/kdeneon.txt +19 -0
- dripfetch/assets/logos/kernelos.txt +19 -0
- dripfetch/assets/logos/kibojoe.txt +13 -0
- dripfetch/assets/logos/kiss.txt +7 -0
- dripfetch/assets/logos/kogaion.txt +20 -0
- dripfetch/assets/logos/korora.txt +16 -0
- dripfetch/assets/logos/krassos.txt +19 -0
- dripfetch/assets/logos/kslinux.txt +11 -0
- dripfetch/assets/logos/kubuntu.txt +20 -0
- dripfetch/assets/logos/kylin.txt +22 -0
- dripfetch/assets/logos/lainos.txt +20 -0
- dripfetch/assets/logos/langitketujuh.txt +11 -0
- dripfetch/assets/logos/laxeros.txt +20 -0
- dripfetch/assets/logos/lede.txt +9 -0
- dripfetch/assets/logos/lfs.txt +18 -0
- dripfetch/assets/logos/libreelec.txt +20 -0
- dripfetch/assets/logos/lilidog.txt +16 -0
- dripfetch/assets/logos/lingmo.txt +20 -0
- dripfetch/assets/logos/linspire.txt +12 -0
- dripfetch/assets/logos/linux.txt +12 -0
- dripfetch/assets/logos/linux_small.txt +7 -0
- dripfetch/assets/logos/linuxlite.txt +20 -0
- dripfetch/assets/logos/linuxlite_small.txt +7 -0
- dripfetch/assets/logos/linuxmint.txt +19 -0
- dripfetch/assets/logos/linuxmint_old.txt +16 -0
- dripfetch/assets/logos/linuxmint_small.txt +7 -0
- dripfetch/assets/logos/live_raizo.txt +20 -0
- dripfetch/assets/logos/lliurex.txt +16 -0
- dripfetch/assets/logos/lmde.txt +17 -0
- dripfetch/assets/logos/locos.txt +18 -0
- dripfetch/assets/logos/lubuntu.txt +20 -0
- dripfetch/assets/logos/lunar.txt +13 -0
- dripfetch/assets/logos/macos.txt +17 -0
- dripfetch/assets/logos/macos2.txt +17 -0
- dripfetch/assets/logos/macos2_small.txt +7 -0
- dripfetch/assets/logos/macos3.txt +16 -0
- dripfetch/assets/logos/macos_small.txt +7 -0
- dripfetch/assets/logos/mageia.txt +19 -0
- dripfetch/assets/logos/mageia_small.txt +7 -0
- dripfetch/assets/logos/magix.txt +19 -0
- dripfetch/assets/logos/magpieos.txt +20 -0
- dripfetch/assets/logos/mainsailos.txt +18 -0
- dripfetch/assets/logos/mainsailos_small.txt +7 -0
- dripfetch/assets/logos/mandriva.txt +15 -0
- dripfetch/assets/logos/manjaro.txt +14 -0
- dripfetch/assets/logos/manjaro_small.txt +7 -0
- dripfetch/assets/logos/massos.txt +18 -0
- dripfetch/assets/logos/matuusos.txt +20 -0
- dripfetch/assets/logos/maui.txt +20 -0
- dripfetch/assets/logos/mauna.txt +15 -0
- dripfetch/assets/logos/meowix.txt +10 -0
- dripfetch/assets/logos/mer.txt +27 -0
- dripfetch/assets/logos/midnightbsd.txt +16 -0
- dripfetch/assets/logos/midos.txt +20 -0
- dripfetch/assets/logos/midos_old.txt +20 -0
- dripfetch/assets/logos/minimal.txt +18 -0
- dripfetch/assets/logos/minix.txt +17 -0
- dripfetch/assets/logos/miracle_linux.txt +16 -0
- dripfetch/assets/logos/mos.txt +18 -0
- dripfetch/assets/logos/msys2.txt +25 -0
- dripfetch/assets/logos/mx.txt +17 -0
- dripfetch/assets/logos/mx2.txt +18 -0
- dripfetch/assets/logos/mx_small.txt +7 -0
- dripfetch/assets/logos/namib.txt +20 -0
- dripfetch/assets/logos/nekos.txt +23 -0
- dripfetch/assets/logos/neptune.txt +17 -0
- dripfetch/assets/logos/netbsd.txt +17 -0
- dripfetch/assets/logos/netbsd2.txt +20 -0
- dripfetch/assets/logos/netbsd_small.txt +8 -0
- dripfetch/assets/logos/netrunner.txt +20 -0
- dripfetch/assets/logos/nexalinux.txt +19 -0
- dripfetch/assets/logos/nitrux.txt +18 -0
- dripfetch/assets/logos/nixos.txt +20 -0
- dripfetch/assets/logos/nixos_old.txt +28 -0
- dripfetch/assets/logos/nixos_old_small.txt +7 -0
- dripfetch/assets/logos/nixos_small.txt +7 -0
- dripfetch/assets/logos/nobara.txt +17 -0
- dripfetch/assets/logos/nomadbsd.txt +13 -0
- dripfetch/assets/logos/nuros.txt +12 -0
- dripfetch/assets/logos/nurunner.txt +19 -0
- dripfetch/assets/logos/nutyx.txt +23 -0
- dripfetch/assets/logos/obarun.txt +19 -0
- dripfetch/assets/logos/obrevenge.txt +18 -0
- dripfetch/assets/logos/obsidianos.txt +16 -0
- dripfetch/assets/logos/omnios.txt +8 -0
- dripfetch/assets/logos/opak.txt +13 -0
- dripfetch/assets/logos/openbsd.txt +23 -0
- dripfetch/assets/logos/openbsd_small.txt +7 -0
- dripfetch/assets/logos/openeuler.txt +23 -0
- dripfetch/assets/logos/openindiana.txt +16 -0
- dripfetch/assets/logos/openkylin.txt +18 -0
- dripfetch/assets/logos/openmamba.txt +21 -0
- dripfetch/assets/logos/openmandriva.txt +22 -0
- dripfetch/assets/logos/openstage.txt +17 -0
- dripfetch/assets/logos/opensuse.txt +18 -0
- dripfetch/assets/logos/opensuse_leap.txt +18 -0
- dripfetch/assets/logos/opensuse_leap_old.txt +16 -0
- dripfetch/assets/logos/opensuse_microos.txt +10 -0
- dripfetch/assets/logos/opensuse_slowroll.txt +20 -0
- dripfetch/assets/logos/opensuse_small.txt +7 -0
- dripfetch/assets/logos/opensuse_tumbleweed.txt +22 -0
- dripfetch/assets/logos/opensuse_tumbleweed_old.txt +13 -0
- dripfetch/assets/logos/opensuse_tumbleweed_small.txt +9 -0
- dripfetch/assets/logos/openwrt.txt +9 -0
- dripfetch/assets/logos/opnsense.txt +20 -0
- dripfetch/assets/logos/oracle.txt +11 -0
- dripfetch/assets/logos/orchid.txt +20 -0
- dripfetch/assets/logos/orchid_small.txt +13 -0
- dripfetch/assets/logos/oreon.txt +22 -0
- dripfetch/assets/logos/os_elbrus.txt +14 -0
- dripfetch/assets/logos/osmc.txt +20 -0
- dripfetch/assets/logos/pacbsd.txt +24 -0
- dripfetch/assets/logos/panwah.txt +21 -0
- dripfetch/assets/logos/parabola.txt +16 -0
- dripfetch/assets/logos/parabola_small.txt +6 -0
- dripfetch/assets/logos/parch.txt +25 -0
- dripfetch/assets/logos/pardus.txt +18 -0
- dripfetch/assets/logos/parrot.txt +24 -0
- dripfetch/assets/logos/parsix.txt +21 -0
- dripfetch/assets/logos/pcbsd.txt +27 -0
- dripfetch/assets/logos/pclinuxos.txt +19 -0
- dripfetch/assets/logos/pearos.txt +21 -0
- dripfetch/assets/logos/pengwin.txt +15 -0
- dripfetch/assets/logos/pentoo.txt +20 -0
- dripfetch/assets/logos/peppermint.txt +21 -0
- dripfetch/assets/logos/peropesis.txt +5 -0
- dripfetch/assets/logos/phyos.txt +17 -0
- dripfetch/assets/logos/pikaos.txt +18 -0
- dripfetch/assets/logos/pisi.txt +19 -0
- dripfetch/assets/logos/pnm_linux.txt +19 -0
- dripfetch/assets/logos/pop.txt +20 -0
- dripfetch/assets/logos/pop_small.txt +8 -0
- dripfetch/assets/logos/porteus.txt +23 -0
- dripfetch/assets/logos/postmarketos.txt +18 -0
- dripfetch/assets/logos/postmarketos_small.txt +9 -0
- dripfetch/assets/logos/proxmox.txt +20 -0
- dripfetch/assets/logos/puffos.txt +12 -0
- dripfetch/assets/logos/puppy.txt +18 -0
- dripfetch/assets/logos/pureos.txt +12 -0
- dripfetch/assets/logos/pureos_small.txt +6 -0
- dripfetch/assets/logos/q4os.txt +19 -0
- dripfetch/assets/logos/qts.txt +14 -0
- dripfetch/assets/logos/qubes.txt +21 -0
- dripfetch/assets/logos/qubyt.txt +15 -0
- dripfetch/assets/logos/quibian.txt +18 -0
- dripfetch/assets/logos/quirinux.txt +17 -0
- dripfetch/assets/logos/radix.txt +18 -0
- dripfetch/assets/logos/raspbian.txt +23 -0
- dripfetch/assets/logos/raspbian_small.txt +10 -0
- dripfetch/assets/logos/ravynos.txt +20 -0
- dripfetch/assets/logos/rebornos.txt +20 -0
- dripfetch/assets/logos/rebornos_small.txt +7 -0
- dripfetch/assets/logos/redcore.txt +16 -0
- dripfetch/assets/logos/redos.txt +18 -0
- dripfetch/assets/logos/redos_small.txt +8 -0
- dripfetch/assets/logos/redstar.txt +18 -0
- dripfetch/assets/logos/refracted_devuan.txt +18 -0
- dripfetch/assets/logos/regata.txt +20 -0
- dripfetch/assets/logos/regolith.txt +18 -0
- dripfetch/assets/logos/rhaymos.txt +14 -0
- dripfetch/assets/logos/rhel.txt +18 -0
- dripfetch/assets/logos/rhel_old.txt +16 -0
- dripfetch/assets/logos/rhel_small.txt +9 -0
- dripfetch/assets/logos/rhino.txt +12 -0
- dripfetch/assets/logos/rocky.txt +19 -0
- dripfetch/assets/logos/rocky_small.txt +12 -0
- dripfetch/assets/logos/rosa.txt +18 -0
- dripfetch/assets/logos/sabayon.txt +18 -0
- dripfetch/assets/logos/sabotage.txt +11 -0
- dripfetch/assets/logos/sailfish.txt +13 -0
- dripfetch/assets/logos/salentos.txt +20 -0
- dripfetch/assets/logos/salientos.txt +20 -0
- dripfetch/assets/logos/salix.txt +18 -0
- dripfetch/assets/logos/sambabox.txt +19 -0
- dripfetch/assets/logos/sasanqua.txt +18 -0
- dripfetch/assets/logos/scientific.txt +20 -0
- dripfetch/assets/logos/semc.txt +9 -0
- dripfetch/assets/logos/septor.txt +20 -0
- dripfetch/assets/logos/serene.txt +20 -0
- dripfetch/assets/logos/serpent_os.txt +18 -0
- dripfetch/assets/logos/sharklinux.txt +15 -0
- dripfetch/assets/logos/shastraos.txt +19 -0
- dripfetch/assets/logos/shebang.txt +20 -0
- dripfetch/assets/logos/siduction.txt +20 -0
- dripfetch/assets/logos/skiffos.txt +9 -0
- dripfetch/assets/logos/slackel.txt +22 -0
- dripfetch/assets/logos/slackware.txt +21 -0
- dripfetch/assets/logos/slackware_small.txt +7 -0
- dripfetch/assets/logos/sleeperos.txt +16 -0
- dripfetch/assets/logos/sleeperos_small.txt +7 -0
- dripfetch/assets/logos/slitaz.txt +17 -0
- dripfetch/assets/logos/smartos.txt +17 -0
- dripfetch/assets/logos/snigdhaos.txt +20 -0
- dripfetch/assets/logos/soda.txt +15 -0
- dripfetch/assets/logos/solaris.txt +8 -0
- dripfetch/assets/logos/solaris_small.txt +5 -0
- dripfetch/assets/logos/solus.txt +20 -0
- dripfetch/assets/logos/source_mage.txt +21 -0
- dripfetch/assets/logos/sparky.txt +20 -0
- dripfetch/assets/logos/spoinkos.txt +5 -0
- dripfetch/assets/logos/star.txt +19 -0
- dripfetch/assets/logos/steamdeck.txt +24 -0
- dripfetch/assets/logos/steamdeck_small.txt +5 -0
- dripfetch/assets/logos/steamos.txt +18 -0
- dripfetch/assets/logos/stock_linux.txt +19 -0
- dripfetch/assets/logos/sulin.txt +20 -0
- dripfetch/assets/logos/summitos.txt +22 -0
- dripfetch/assets/logos/suse.txt +11 -0
- dripfetch/assets/logos/swagarch.txt +15 -0
- dripfetch/assets/logos/t2.txt +14 -0
- dripfetch/assets/logos/t2_small.txt +6 -0
- dripfetch/assets/logos/tails.txt +19 -0
- dripfetch/assets/logos/tatra.txt +15 -0
- dripfetch/assets/logos/tearch.txt +21 -0
- dripfetch/assets/logos/templeos.txt +20 -0
- dripfetch/assets/logos/tileos.txt +20 -0
- dripfetch/assets/logos/torizoncore.txt +29 -0
- dripfetch/assets/logos/trisquel.txt +17 -0
- dripfetch/assets/logos/truenas_scale.txt +18 -0
- dripfetch/assets/logos/tuxedo_os.txt +16 -0
- dripfetch/assets/logos/twister.txt +23 -0
- dripfetch/assets/logos/ublinux.txt +19 -0
- dripfetch/assets/logos/ublinux_small.txt +11 -0
- dripfetch/assets/logos/ubuntu.txt +20 -0
- dripfetch/assets/logos/ubuntu_budgie.txt +20 -0
- dripfetch/assets/logos/ubuntu_cinnamon.txt +20 -0
- dripfetch/assets/logos/ubuntu_gnome.txt +16 -0
- dripfetch/assets/logos/ubuntu_kylin.txt +20 -0
- dripfetch/assets/logos/ubuntu_mate.txt +20 -0
- dripfetch/assets/logos/ubuntu_old.txt +20 -0
- dripfetch/assets/logos/ubuntu_old2.txt +18 -0
- dripfetch/assets/logos/ubuntu_old2_small.txt +6 -0
- dripfetch/assets/logos/ubuntu_small.txt +11 -0
- dripfetch/assets/logos/ubuntu_studio.txt +20 -0
- dripfetch/assets/logos/ubuntu_sway.txt +20 -0
- dripfetch/assets/logos/ubuntu_touch.txt +7 -0
- dripfetch/assets/logos/ubuntu_unity.txt +25 -0
- dripfetch/assets/logos/ultramarine.txt +20 -0
- dripfetch/assets/logos/ultramarine_small.txt +14 -0
- dripfetch/assets/logos/unifi.txt +6 -0
- dripfetch/assets/logos/univalent.txt +18 -0
- dripfetch/assets/logos/univention.txt +20 -0
- dripfetch/assets/logos/unknown.txt +18 -0
- dripfetch/assets/logos/uos.txt +20 -0
- dripfetch/assets/logos/urukos.txt +20 -0
- dripfetch/assets/logos/uwuntu.txt +20 -0
- dripfetch/assets/logos/valhalla.txt +10 -0
- dripfetch/assets/logos/vanilla.txt +18 -0
- dripfetch/assets/logos/vanilla2.txt +16 -0
- dripfetch/assets/logos/vanilla_small.txt +7 -0
- dripfetch/assets/logos/venom.txt +19 -0
- dripfetch/assets/logos/venom_small.txt +11 -0
- dripfetch/assets/logos/vnux.txt +20 -0
- dripfetch/assets/logos/void.txt +18 -0
- dripfetch/assets/logos/void2.txt +25 -0
- dripfetch/assets/logos/void2_small.txt +7 -0
- dripfetch/assets/logos/void_small.txt +7 -0
- dripfetch/assets/logos/vzlinux.txt +20 -0
- dripfetch/assets/logos/wii_linux.txt +16 -0
- dripfetch/assets/logos/windows.txt +16 -0
- dripfetch/assets/logos/windows_11.txt +17 -0
- dripfetch/assets/logos/windows_11_small.txt +7 -0
- dripfetch/assets/logos/windows_2025.txt +17 -0
- dripfetch/assets/logos/windows_8.txt +19 -0
- dripfetch/assets/logos/windows_95.txt +18 -0
- dripfetch/assets/logos/wolfos.txt +5 -0
- dripfetch/assets/logos/xcp_ng.txt +15 -0
- dripfetch/assets/logos/xenia.txt +15 -0
- dripfetch/assets/logos/xenia_old.txt +21 -0
- dripfetch/assets/logos/xeroarch.txt +19 -0
- dripfetch/assets/logos/xferience.txt +19 -0
- dripfetch/assets/logos/xray_os.txt +21 -0
- dripfetch/assets/logos/xubuntu.txt +19 -0
- dripfetch/assets/logos/yiffos.txt +19 -0
- dripfetch/assets/logos/zorin.txt +17 -0
- dripfetch/assets/logos/zos.txt +7 -0
- dripfetch/box/__init__.py +5 -0
- dripfetch/box/base.py +24 -0
- dripfetch/box/borders.py +41 -0
- dripfetch/box/colors.py +110 -0
- dripfetch/box/manager.py +181 -0
- dripfetch/box/placement.py +40 -0
- dripfetch/box/types/__init__.py +5 -0
- dripfetch/box/types/clock.py +487 -0
- dripfetch/box/types/logo.py +62 -0
- dripfetch/box/types/sysinfo.py +570 -0
- dripfetch/box/types/text.py +16 -0
- dripfetch/box/types/weather.py +181 -0
- dripfetch/cli.py +58 -0
- dripfetch/config.py +405 -0
- dripfetch/default_config.yaml +80 -0
- dripfetch/rain/__init__.py +3 -0
- dripfetch/rain/collision.py +23 -0
- dripfetch/rain/colors.py +51 -0
- dripfetch/rain/drop.py +16 -0
- dripfetch/rain/engine.py +190 -0
- dripfetch/rain/movement.py +46 -0
- dripfetch/rain/spawning.py +59 -0
- dripfetch/terminal.py +193 -0
- dripfetch-0.1.0.dist-info/METADATA +47 -0
- dripfetch-0.1.0.dist-info/RECORD +519 -0
- dripfetch-0.1.0.dist-info/WHEEL +5 -0
- dripfetch-0.1.0.dist-info/entry_points.txt +2 -0
- dripfetch-0.1.0.dist-info/licenses/LICENSE +21 -0
- dripfetch-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import threading
|
|
3
|
+
import time
|
|
4
|
+
import urllib.parse
|
|
5
|
+
import urllib.request
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
|
|
8
|
+
from ..base import BaseBox
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class WeatherBox(BaseBox):
|
|
12
|
+
WIDTH = 40
|
|
13
|
+
HEIGHT = 7
|
|
14
|
+
CACHE_TIME = 1800
|
|
15
|
+
TIMEOUT = 10
|
|
16
|
+
|
|
17
|
+
CODES = {
|
|
18
|
+
0: "Clear", 1: "Mostly Clear", 2: "Partly Cloudy", 3: "Cloudy",
|
|
19
|
+
45: "Fog", 48: "Fog", 51: "Drizzle", 53: "Drizzle", 55: "Heavy Drizzle",
|
|
20
|
+
56: "Freezing Drizzle", 57: "Freezing Drizzle", 61: "Light Rain",
|
|
21
|
+
63: "Rain", 65: "Heavy Rain", 66: "Freezing Rain", 67: "Heavy Rain",
|
|
22
|
+
71: "Light Snow", 73: "Snow", 75: "Heavy Snow", 77: "Snow Grains",
|
|
23
|
+
80: "Light Showers", 81: "Showers", 82: "Heavy Showers",
|
|
24
|
+
85: "Snow Showers", 86: "Heavy Snow", 95: "Thunderstorm",
|
|
25
|
+
96: "Thunderstorm", 99: "Thunderstorm",
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
def __init__(self, stdscr, config, boxes, colors, renderer=None):
|
|
29
|
+
super().__init__(stdscr, config, boxes, colors, renderer)
|
|
30
|
+
self.location = config.get("location", "")
|
|
31
|
+
self.latitude = config.get("latitude")
|
|
32
|
+
self.longitude = config.get("longitude")
|
|
33
|
+
self.location_name = self.location
|
|
34
|
+
self.days = []
|
|
35
|
+
self.error = None
|
|
36
|
+
self.loading = True
|
|
37
|
+
self.last_attempt = 0
|
|
38
|
+
self.last_update = 0
|
|
39
|
+
self._thread = None
|
|
40
|
+
self._lock = threading.Lock()
|
|
41
|
+
self._start_fetch()
|
|
42
|
+
|
|
43
|
+
def _start_fetch(self):
|
|
44
|
+
now = time.monotonic()
|
|
45
|
+
if self._thread and self._thread.is_alive():
|
|
46
|
+
return
|
|
47
|
+
if now - self.last_attempt < self.CACHE_TIME:
|
|
48
|
+
return
|
|
49
|
+
self.last_attempt = now
|
|
50
|
+
self.loading = True
|
|
51
|
+
self._thread = threading.Thread(target=self._fetch, daemon=True)
|
|
52
|
+
self._thread.start()
|
|
53
|
+
|
|
54
|
+
def _geocode(self):
|
|
55
|
+
if self.latitude is not None and self.longitude is not None:
|
|
56
|
+
return float(self.latitude), float(self.longitude), self.location
|
|
57
|
+
if not self.location:
|
|
58
|
+
raise ValueError("No location configured")
|
|
59
|
+
|
|
60
|
+
query = urllib.parse.urlencode({
|
|
61
|
+
"name": self.location,
|
|
62
|
+
"count": 1,
|
|
63
|
+
"language": "en",
|
|
64
|
+
"format": "json",
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
with urllib.request.urlopen(
|
|
68
|
+
f"https://geocoding-api.open-meteo.com/v1/search?{query}",
|
|
69
|
+
timeout=self.TIMEOUT,
|
|
70
|
+
) as response:
|
|
71
|
+
results = json.load(response).get("results", [])
|
|
72
|
+
|
|
73
|
+
if not results:
|
|
74
|
+
raise ValueError(f"Location not found: {self.location}")
|
|
75
|
+
|
|
76
|
+
result = results[0]
|
|
77
|
+
name = result.get("name", self.location)
|
|
78
|
+
country = result.get("country", "")
|
|
79
|
+
return result["latitude"], result["longitude"], f"{name}, {country}".strip(", ")
|
|
80
|
+
|
|
81
|
+
def _fetch(self):
|
|
82
|
+
try:
|
|
83
|
+
latitude, longitude, location = self._geocode()
|
|
84
|
+
params = urllib.parse.urlencode({
|
|
85
|
+
"latitude": latitude,
|
|
86
|
+
"longitude": longitude,
|
|
87
|
+
"daily": "weather_code,temperature_2m_max,temperature_2m_min,precipitation_probability_max",
|
|
88
|
+
"timezone": "auto",
|
|
89
|
+
"forecast_days": 5,
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
with urllib.request.urlopen(
|
|
93
|
+
f"https://api.open-meteo.com/v1/forecast?{params}",
|
|
94
|
+
timeout=self.TIMEOUT,
|
|
95
|
+
) as response:
|
|
96
|
+
daily = json.load(response)["daily"]
|
|
97
|
+
|
|
98
|
+
days = []
|
|
99
|
+
for i, value in enumerate(daily["time"]):
|
|
100
|
+
date = datetime.fromisoformat(value)
|
|
101
|
+
days.append({
|
|
102
|
+
"day": "Today" if i == 0 else date.strftime("%a"),
|
|
103
|
+
"condition": self.CODES.get(daily["weather_code"][i], "Unknown"),
|
|
104
|
+
"high": self._value(daily["temperature_2m_max"][i]),
|
|
105
|
+
"low": self._value(daily["temperature_2m_min"][i]),
|
|
106
|
+
"rain": self._value(daily["precipitation_probability_max"][i]),
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
with self._lock:
|
|
110
|
+
self.days = days
|
|
111
|
+
self.location_name = location
|
|
112
|
+
self.error = None
|
|
113
|
+
self.loading = False
|
|
114
|
+
self.last_update = time.monotonic()
|
|
115
|
+
|
|
116
|
+
except Exception as exc:
|
|
117
|
+
with self._lock:
|
|
118
|
+
self.error = str(exc)
|
|
119
|
+
self.loading = False
|
|
120
|
+
|
|
121
|
+
@staticmethod
|
|
122
|
+
def _value(value):
|
|
123
|
+
return "--" if value is None else str(round(value))
|
|
124
|
+
|
|
125
|
+
def update(self):
|
|
126
|
+
if time.monotonic() - self.last_update >= self.CACHE_TIME:
|
|
127
|
+
self._start_fetch()
|
|
128
|
+
|
|
129
|
+
def _format(self, day):
|
|
130
|
+
condition = day["condition"][:14]
|
|
131
|
+
return f"{day['day']:<6} {condition:<14} {day['high']:>2}°/{day['low']:<2}° {day['rain']:>3}%"
|
|
132
|
+
|
|
133
|
+
def draw_content(self, x, y, width, height):
|
|
134
|
+
if width <= 0 or height <= 0:
|
|
135
|
+
return
|
|
136
|
+
|
|
137
|
+
with self._lock:
|
|
138
|
+
days = list(self.days)
|
|
139
|
+
loading = self.loading
|
|
140
|
+
location = self.location_name
|
|
141
|
+
|
|
142
|
+
if not days:
|
|
143
|
+
text = "Fetching weather..." if loading else "Weather unavailable"
|
|
144
|
+
self.renderer.draw(x, y, text[:width], self.colors.body)
|
|
145
|
+
return
|
|
146
|
+
|
|
147
|
+
self.renderer.draw(
|
|
148
|
+
x, y,
|
|
149
|
+
f"WEATHER / {location.upper()}"[:width],
|
|
150
|
+
self.colors.title,
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
if height < 2:
|
|
154
|
+
return
|
|
155
|
+
|
|
156
|
+
self.renderer.draw(
|
|
157
|
+
x, y + 1,
|
|
158
|
+
"─" * min(width, self.WIDTH),
|
|
159
|
+
self.colors.line,
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
if height < 3:
|
|
163
|
+
return
|
|
164
|
+
|
|
165
|
+
self.renderer.draw(
|
|
166
|
+
x, y + 2,
|
|
167
|
+
f"{'DAY':<6} {'CONDITION':<14} {'TEMP':>5} {'RAIN':>4}"[:width],
|
|
168
|
+
self.colors.line,
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
for row, day in enumerate(days[:5], 3):
|
|
172
|
+
if row >= height:
|
|
173
|
+
break
|
|
174
|
+
self.renderer.draw(
|
|
175
|
+
x, y + row,
|
|
176
|
+
self._format(day)[:width],
|
|
177
|
+
self.colors.body,
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
def dimensions(self):
|
|
181
|
+
return self.WIDTH, self.HEIGHT
|
dripfetch/cli.py
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
import curses
|
|
3
|
+
|
|
4
|
+
from . import __version__
|
|
5
|
+
from .app import App
|
|
6
|
+
from .config import (
|
|
7
|
+
CONFIG_PATH,
|
|
8
|
+
create_default_config,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def main():
|
|
13
|
+
parser = argparse.ArgumentParser(
|
|
14
|
+
prog="dripfetch",
|
|
15
|
+
description=(
|
|
16
|
+
"A customizable terminal system information display with animated rain."
|
|
17
|
+
),
|
|
18
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
19
|
+
epilog="""controls:
|
|
20
|
+
q quit
|
|
21
|
+
space pause/resume rain
|
|
22
|
+
mouse select box
|
|
23
|
+
w/a/s/d move selected box
|
|
24
|
+
esc deselect selected box
|
|
25
|
+
configuration:
|
|
26
|
+
--init-config restore the default configuration
|
|
27
|
+
--config-path show the configuration file currently in use
|
|
28
|
+
-c PATH use a custom configuration file""",
|
|
29
|
+
)
|
|
30
|
+
parser.add_argument(
|
|
31
|
+
"-v",
|
|
32
|
+
"--version",
|
|
33
|
+
action="version",
|
|
34
|
+
version=__version__,
|
|
35
|
+
)
|
|
36
|
+
parser.add_argument(
|
|
37
|
+
"--init-config",
|
|
38
|
+
action="store_true",
|
|
39
|
+
)
|
|
40
|
+
parser.add_argument(
|
|
41
|
+
"--config-path",
|
|
42
|
+
action="store_true",
|
|
43
|
+
)
|
|
44
|
+
parser.add_argument(
|
|
45
|
+
"-c",
|
|
46
|
+
"--config",
|
|
47
|
+
metavar="PATH",
|
|
48
|
+
)
|
|
49
|
+
args = parser.parse_args()
|
|
50
|
+
if args.init_config:
|
|
51
|
+
create_default_config(force=True)
|
|
52
|
+
print(CONFIG_PATH)
|
|
53
|
+
return
|
|
54
|
+
config_path = args.config or CONFIG_PATH
|
|
55
|
+
if args.config_path:
|
|
56
|
+
print(config_path)
|
|
57
|
+
return
|
|
58
|
+
curses.wrapper(App(config_path).run)
|
dripfetch/config.py
ADDED
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import re
|
|
3
|
+
import tempfile
|
|
4
|
+
from importlib.resources import files
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
from ruamel.yaml import YAML
|
|
8
|
+
from ruamel.yaml.error import YAMLError
|
|
9
|
+
|
|
10
|
+
CONFIG_DIR = Path.home() / ".config" / "dripfetch"
|
|
11
|
+
CONFIG_PATH = CONFIG_DIR / "config.yaml"
|
|
12
|
+
COLOR_RE = re.compile(r"^#[0-9a-fA-F]{6}([0-9a-fA-F]{2})?$")
|
|
13
|
+
BOX_TYPES = {"text", "clock", "sysinfo", "logo", "weather"}
|
|
14
|
+
BORDER_TYPES = {"single", "double"}
|
|
15
|
+
CLOCK_STYLES = {"single", "double"}
|
|
16
|
+
CLOCK_SIZES = {"medium", "big"}
|
|
17
|
+
DEFAULT_BACKGROUND = "#000000FF"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ConfigError(ValueError):
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _yaml():
|
|
25
|
+
yaml = YAML()
|
|
26
|
+
yaml.preserve_quotes = True
|
|
27
|
+
yaml.default_flow_style = False
|
|
28
|
+
yaml.indent(mapping=2, sequence=4, offset=2)
|
|
29
|
+
return yaml
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _error(path, message):
|
|
33
|
+
raise ConfigError(f"{path}: {message}")
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _mapping(value, path):
|
|
37
|
+
if not isinstance(value, dict):
|
|
38
|
+
_error(path, "must be a mapping")
|
|
39
|
+
return value
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _string(value, path):
|
|
43
|
+
if not isinstance(value, str):
|
|
44
|
+
_error(path, "must be a string")
|
|
45
|
+
return value
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _bool(value, path):
|
|
49
|
+
if not isinstance(value, bool):
|
|
50
|
+
_error(path, "must be true or false")
|
|
51
|
+
return value
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _number(value, path):
|
|
55
|
+
if isinstance(value, bool) or not isinstance(value, (int, float)):
|
|
56
|
+
_error(path, "must be a number")
|
|
57
|
+
return value
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _integer(value, path):
|
|
61
|
+
if isinstance(value, bool) or not isinstance(value, int):
|
|
62
|
+
_error(path, "must be an integer")
|
|
63
|
+
return value
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def _color(value, path):
|
|
67
|
+
_string(value, path)
|
|
68
|
+
if not COLOR_RE.fullmatch(value):
|
|
69
|
+
_error(path, "must be #RRGGBB or #RRGGBBAA")
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _enum(value, path, choices):
|
|
73
|
+
_string(value, path)
|
|
74
|
+
if value not in choices:
|
|
75
|
+
_error(path, f"must be one of: {', '.join(sorted(choices))}")
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _weighted_list(value, path, value_type):
|
|
79
|
+
if not isinstance(value, list) or not value:
|
|
80
|
+
_error(path, "must be a non-empty list")
|
|
81
|
+
total = 0
|
|
82
|
+
for index, item in enumerate(value):
|
|
83
|
+
item_path = f"{path}[{index}]"
|
|
84
|
+
if not isinstance(item, (list, tuple)) or len(item) != 2:
|
|
85
|
+
_error(item_path, "must contain exactly two values")
|
|
86
|
+
weight, item_value = item
|
|
87
|
+
_number(weight, f"{item_path}[0]")
|
|
88
|
+
if weight <= 0:
|
|
89
|
+
_error(f"{item_path}[0]", "must be greater than 0")
|
|
90
|
+
total += weight
|
|
91
|
+
if value_type == "color":
|
|
92
|
+
_color(item_value, f"{item_path}[1]")
|
|
93
|
+
elif value_type == "integer":
|
|
94
|
+
_integer(item_value, f"{item_path}[1]")
|
|
95
|
+
else:
|
|
96
|
+
_number(item_value, f"{item_path}[1]")
|
|
97
|
+
if abs(total - 1) > 0.001:
|
|
98
|
+
_error(path, "weights must sum to 1")
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def _position(value, path):
|
|
102
|
+
value = _mapping(value, path)
|
|
103
|
+
for key in ("horizontal", "vertical"):
|
|
104
|
+
if key in value:
|
|
105
|
+
_integer(value[key], f"{path}.{key}")
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def _validate_text(item, path):
|
|
109
|
+
if "text" in item:
|
|
110
|
+
_string(item["text"], f"{path}.text")
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def _validate_clock(item, path):
|
|
114
|
+
for key, choices in (
|
|
115
|
+
("clock_style", CLOCK_STYLES),
|
|
116
|
+
("clock_size", CLOCK_SIZES),
|
|
117
|
+
):
|
|
118
|
+
if key in item:
|
|
119
|
+
_enum(item[key], f"{path}.{key}", choices)
|
|
120
|
+
for key in (
|
|
121
|
+
"clock_24h",
|
|
122
|
+
"show_seconds",
|
|
123
|
+
"show_am_pm",
|
|
124
|
+
"blink_colon",
|
|
125
|
+
"show_date",
|
|
126
|
+
):
|
|
127
|
+
if key in item:
|
|
128
|
+
_bool(item[key], f"{path}.{key}")
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def _validate_sysinfo(item, path):
|
|
132
|
+
if "colors" not in item:
|
|
133
|
+
return
|
|
134
|
+
colors = _mapping(item["colors"], f"{path}.colors")
|
|
135
|
+
for key in ("text", "title", "line"):
|
|
136
|
+
if key in colors:
|
|
137
|
+
_color(colors[key], f"{path}.colors.{key}")
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def _validate_logo(item, path):
|
|
141
|
+
if "logo" in item:
|
|
142
|
+
logo = _string(item["logo"], f"{path}.logo")
|
|
143
|
+
if not logo:
|
|
144
|
+
_error(f"{path}.logo", "must not be empty")
|
|
145
|
+
if "colors" in item:
|
|
146
|
+
colors = item["colors"]
|
|
147
|
+
if not isinstance(colors, list) or not colors:
|
|
148
|
+
_error(f"{path}.colors", "must be a non-empty list")
|
|
149
|
+
for index, color in enumerate(colors):
|
|
150
|
+
_color(color, f"{path}.colors[{index}]")
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def _validate_box(item, index):
|
|
154
|
+
path = f"boxes.items[{index}]"
|
|
155
|
+
item = _mapping(item, path)
|
|
156
|
+
box_type = item.get("type", "text")
|
|
157
|
+
_enum(box_type, f"{path}.type", BOX_TYPES)
|
|
158
|
+
if "border" in item:
|
|
159
|
+
_enum(item["border"], f"{path}.border", BORDER_TYPES)
|
|
160
|
+
if "position" in item:
|
|
161
|
+
_position(item["position"], f"{path}.position")
|
|
162
|
+
validators = {
|
|
163
|
+
"text": _validate_text,
|
|
164
|
+
"clock": _validate_clock,
|
|
165
|
+
"sysinfo": _validate_sysinfo,
|
|
166
|
+
"logo": _validate_logo,
|
|
167
|
+
"weather": _validate_weather,
|
|
168
|
+
}
|
|
169
|
+
validators[box_type](item, path)
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def validate_config(config):
|
|
173
|
+
config = _mapping(config, "config")
|
|
174
|
+
if "background" in config:
|
|
175
|
+
_color(config["background"], "background")
|
|
176
|
+
|
|
177
|
+
rain = _mapping(config.get("rain", {}), "rain")
|
|
178
|
+
if "collision" in rain:
|
|
179
|
+
_bool(rain["collision"], "rain.collision")
|
|
180
|
+
|
|
181
|
+
if "intensity" in rain:
|
|
182
|
+
intensity = _integer(rain["intensity"], "rain.intensity")
|
|
183
|
+
if intensity < 0:
|
|
184
|
+
_error(
|
|
185
|
+
"rain.intensity",
|
|
186
|
+
"must be greater than or equal to 0",
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
if "character" in rain:
|
|
190
|
+
character = _string(
|
|
191
|
+
rain["character"],
|
|
192
|
+
"rain.character",
|
|
193
|
+
)
|
|
194
|
+
if not character:
|
|
195
|
+
_error(
|
|
196
|
+
"rain.character",
|
|
197
|
+
"must not be empty",
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
for key, value_type in (
|
|
201
|
+
("colors", "color"),
|
|
202
|
+
("speeds", "integer"),
|
|
203
|
+
("lengths", "integer"),
|
|
204
|
+
):
|
|
205
|
+
if key in rain:
|
|
206
|
+
_weighted_list(
|
|
207
|
+
rain[key],
|
|
208
|
+
f"rain.{key}",
|
|
209
|
+
value_type,
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
boxes = _mapping(
|
|
213
|
+
config.get("boxes", {}),
|
|
214
|
+
"boxes",
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
if "border" in boxes:
|
|
218
|
+
_enum(
|
|
219
|
+
boxes["border"],
|
|
220
|
+
"boxes.border",
|
|
221
|
+
BORDER_TYPES,
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
for key in (
|
|
225
|
+
"border_color",
|
|
226
|
+
"text_color",
|
|
227
|
+
"accent_color",
|
|
228
|
+
):
|
|
229
|
+
if key in boxes:
|
|
230
|
+
_color(
|
|
231
|
+
boxes[key],
|
|
232
|
+
f"boxes.{key}",
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
if "padding" in boxes:
|
|
236
|
+
padding = _mapping(
|
|
237
|
+
boxes["padding"],
|
|
238
|
+
"boxes.padding",
|
|
239
|
+
)
|
|
240
|
+
for key in (
|
|
241
|
+
"horizontal",
|
|
242
|
+
"vertical",
|
|
243
|
+
):
|
|
244
|
+
if key in padding:
|
|
245
|
+
value = _integer(
|
|
246
|
+
padding[key],
|
|
247
|
+
f"boxes.padding.{key}",
|
|
248
|
+
)
|
|
249
|
+
if value < 0:
|
|
250
|
+
_error(
|
|
251
|
+
f"boxes.padding.{key}",
|
|
252
|
+
"must be greater than or equal to 0",
|
|
253
|
+
)
|
|
254
|
+
|
|
255
|
+
items = boxes.get("items", [])
|
|
256
|
+
if not isinstance(items, list):
|
|
257
|
+
_error(
|
|
258
|
+
"boxes.items",
|
|
259
|
+
"must be a list",
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
for index, item in enumerate(items):
|
|
263
|
+
_validate_box(item, index)
|
|
264
|
+
|
|
265
|
+
return config
|
|
266
|
+
|
|
267
|
+
def _validate_weather(item, path):
|
|
268
|
+
if "location" in item:
|
|
269
|
+
location = _string(item["location"], f"{path}.location")
|
|
270
|
+
if not location:
|
|
271
|
+
_error(f"{path}.location", "must not be empty")
|
|
272
|
+
|
|
273
|
+
if "latitude" in item:
|
|
274
|
+
latitude = item["latitude"]
|
|
275
|
+
if not isinstance(latitude, (int, float)):
|
|
276
|
+
_error(f"{path}.latitude", "must be a number")
|
|
277
|
+
elif not -90 <= latitude <= 90:
|
|
278
|
+
_error(f"{path}.latitude", "must be between -90 and 90")
|
|
279
|
+
|
|
280
|
+
if "longitude" in item:
|
|
281
|
+
longitude = item["longitude"]
|
|
282
|
+
if not isinstance(longitude, (int, float)):
|
|
283
|
+
_error(f"{path}.longitude", "must be a number")
|
|
284
|
+
elif not -180 <= longitude <= 180:
|
|
285
|
+
_error(f"{path}.longitude", "must be between -180 and 180")
|
|
286
|
+
|
|
287
|
+
if "location" not in item and not (
|
|
288
|
+
"latitude" in item and "longitude" in item
|
|
289
|
+
):
|
|
290
|
+
_error(path, "requires location or latitude and longitude")
|
|
291
|
+
|
|
292
|
+
def _parse(text, path):
|
|
293
|
+
try:
|
|
294
|
+
config = _yaml().load(text)
|
|
295
|
+
except YAMLError as exc:
|
|
296
|
+
raise ConfigError(f"{path}: invalid YAML: {exc}") from exc
|
|
297
|
+
|
|
298
|
+
if config is None:
|
|
299
|
+
raise ConfigError(f"{path}: configuration is empty")
|
|
300
|
+
|
|
301
|
+
return validate_config(config)
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def _default_config():
|
|
305
|
+
return files("dripfetch").joinpath(
|
|
306
|
+
"default_config.yaml",
|
|
307
|
+
).read_text(encoding="utf-8")
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
def save_config(config, path=CONFIG_PATH):
|
|
311
|
+
path = Path(path).expanduser()
|
|
312
|
+
validate_config(config)
|
|
313
|
+
|
|
314
|
+
path.parent.mkdir(
|
|
315
|
+
parents=True,
|
|
316
|
+
exist_ok=True,
|
|
317
|
+
)
|
|
318
|
+
|
|
319
|
+
mode = path.stat().st_mode if path.exists() else 0o644
|
|
320
|
+
temporary = None
|
|
321
|
+
|
|
322
|
+
try:
|
|
323
|
+
with tempfile.NamedTemporaryFile(
|
|
324
|
+
mode="w",
|
|
325
|
+
encoding="utf-8",
|
|
326
|
+
dir=path.parent,
|
|
327
|
+
prefix=f".{path.name}.",
|
|
328
|
+
suffix=".tmp",
|
|
329
|
+
delete=False,
|
|
330
|
+
) as file:
|
|
331
|
+
temporary = Path(file.name)
|
|
332
|
+
|
|
333
|
+
os.chmod(
|
|
334
|
+
temporary,
|
|
335
|
+
mode & 0o777,
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
_yaml().dump(
|
|
339
|
+
config,
|
|
340
|
+
file,
|
|
341
|
+
)
|
|
342
|
+
|
|
343
|
+
file.flush()
|
|
344
|
+
os.fsync(file.fileno())
|
|
345
|
+
|
|
346
|
+
os.replace(
|
|
347
|
+
temporary,
|
|
348
|
+
path,
|
|
349
|
+
)
|
|
350
|
+
|
|
351
|
+
try:
|
|
352
|
+
directory = os.open(
|
|
353
|
+
path.parent,
|
|
354
|
+
os.O_RDONLY,
|
|
355
|
+
)
|
|
356
|
+
try:
|
|
357
|
+
os.fsync(directory)
|
|
358
|
+
finally:
|
|
359
|
+
os.close(directory)
|
|
360
|
+
except OSError:
|
|
361
|
+
pass
|
|
362
|
+
|
|
363
|
+
finally:
|
|
364
|
+
if temporary:
|
|
365
|
+
temporary.unlink(missing_ok=True)
|
|
366
|
+
|
|
367
|
+
|
|
368
|
+
def create_default_config(force=False):
|
|
369
|
+
if CONFIG_PATH.exists() and not force:
|
|
370
|
+
return False
|
|
371
|
+
|
|
372
|
+
save_config(
|
|
373
|
+
_parse(
|
|
374
|
+
_default_config(),
|
|
375
|
+
"default_config.yaml",
|
|
376
|
+
),
|
|
377
|
+
CONFIG_PATH,
|
|
378
|
+
)
|
|
379
|
+
|
|
380
|
+
return True
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
def load_config(path=None):
|
|
384
|
+
path = Path(path or CONFIG_PATH).expanduser()
|
|
385
|
+
|
|
386
|
+
if not path.exists():
|
|
387
|
+
if path != CONFIG_PATH:
|
|
388
|
+
raise FileNotFoundError(
|
|
389
|
+
f"Configuration file not found: {path}",
|
|
390
|
+
)
|
|
391
|
+
create_default_config()
|
|
392
|
+
|
|
393
|
+
try:
|
|
394
|
+
text = path.read_text(
|
|
395
|
+
encoding="utf-8",
|
|
396
|
+
)
|
|
397
|
+
except OSError as exc:
|
|
398
|
+
raise ConfigError(
|
|
399
|
+
f"{path}: cannot read configuration: {exc}",
|
|
400
|
+
) from exc
|
|
401
|
+
|
|
402
|
+
return _parse(
|
|
403
|
+
text,
|
|
404
|
+
path,
|
|
405
|
+
)
|