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.
Files changed (519) hide show
  1. dripfetch/__init__.py +1 -0
  2. dripfetch/__main__.py +4 -0
  3. dripfetch/app.py +111 -0
  4. dripfetch/assets/logos/adelie.txt +16 -0
  5. dripfetch/assets/logos/aeon.txt +14 -0
  6. dripfetch/assets/logos/aeros.txt +21 -0
  7. dripfetch/assets/logos/aerynos.txt +16 -0
  8. dripfetch/assets/logos/afterglow.txt +15 -0
  9. dripfetch/assets/logos/aix.txt +20 -0
  10. dripfetch/assets/logos/almalinux.txt +20 -0
  11. dripfetch/assets/logos/alpine.txt +20 -0
  12. dripfetch/assets/logos/alpine2.txt +16 -0
  13. dripfetch/assets/logos/alpine2_small.txt +6 -0
  14. dripfetch/assets/logos/alpine3_small.txt +6 -0
  15. dripfetch/assets/logos/alpine_small.txt +6 -0
  16. dripfetch/assets/logos/alter.txt +20 -0
  17. dripfetch/assets/logos/altlinux.txt +22 -0
  18. dripfetch/assets/logos/amazon.txt +19 -0
  19. dripfetch/assets/logos/amazon_linux.txt +10 -0
  20. dripfetch/assets/logos/amogos.txt +19 -0
  21. dripfetch/assets/logos/anarchy.txt +28 -0
  22. dripfetch/assets/logos/android.txt +18 -0
  23. dripfetch/assets/logos/android_small.txt +6 -0
  24. dripfetch/assets/logos/anduinos.txt +19 -0
  25. dripfetch/assets/logos/antergos.txt +19 -0
  26. dripfetch/assets/logos/antix.txt +12 -0
  27. dripfetch/assets/logos/anushos.txt +20 -0
  28. dripfetch/assets/logos/aoscos.txt +17 -0
  29. dripfetch/assets/logos/aoscos_old.txt +20 -0
  30. dripfetch/assets/logos/aoscosretro.txt +18 -0
  31. dripfetch/assets/logos/aoscosretro_small.txt +9 -0
  32. dripfetch/assets/logos/aperture.txt +20 -0
  33. dripfetch/assets/logos/apricity.txt +18 -0
  34. dripfetch/assets/logos/arch.txt +19 -0
  35. dripfetch/assets/logos/arch2.txt +19 -0
  36. dripfetch/assets/logos/arch3.txt +19 -0
  37. dripfetch/assets/logos/arch_old.txt +16 -0
  38. dripfetch/assets/logos/arch_small.txt +7 -0
  39. dripfetch/assets/logos/archbox.txt +19 -0
  40. dripfetch/assets/logos/archcraft.txt +20 -0
  41. dripfetch/assets/logos/archcraft2.txt +20 -0
  42. dripfetch/assets/logos/archlabs.txt +21 -0
  43. dripfetch/assets/logos/archstrike.txt +17 -0
  44. dripfetch/assets/logos/arco.txt +20 -0
  45. dripfetch/assets/logos/arco_small.txt +11 -0
  46. dripfetch/assets/logos/arkane.txt +23 -0
  47. dripfetch/assets/logos/armbian.txt +22 -0
  48. dripfetch/assets/logos/armbian2.txt +14 -0
  49. dripfetch/assets/logos/arselinux.txt +15 -0
  50. dripfetch/assets/logos/artix.txt +20 -0
  51. dripfetch/assets/logos/artix2_small.txt +13 -0
  52. dripfetch/assets/logos/artix_small.txt +7 -0
  53. dripfetch/assets/logos/arya.txt +15 -0
  54. dripfetch/assets/logos/asahi.txt +18 -0
  55. dripfetch/assets/logos/asahi2.txt +18 -0
  56. dripfetch/assets/logos/aster.txt +18 -0
  57. dripfetch/assets/logos/asteroidos.txt +17 -0
  58. dripfetch/assets/logos/astos.txt +23 -0
  59. dripfetch/assets/logos/astra_linux.txt +22 -0
  60. dripfetch/assets/logos/athenaos.txt +29 -0
  61. dripfetch/assets/logos/athenaos_old.txt +24 -0
  62. dripfetch/assets/logos/aurora.txt +28 -0
  63. dripfetch/assets/logos/axos.txt +16 -0
  64. dripfetch/assets/logos/azos.txt +17 -0
  65. dripfetch/assets/logos/bedrock.txt +17 -0
  66. dripfetch/assets/logos/bedrock_small.txt +6 -0
  67. dripfetch/assets/logos/biglinux.txt +19 -0
  68. dripfetch/assets/logos/bitrig.txt +17 -0
  69. dripfetch/assets/logos/blackarch.txt +21 -0
  70. dripfetch/assets/logos/blackmesa.txt +20 -0
  71. dripfetch/assets/logos/blackpanther.txt +23 -0
  72. dripfetch/assets/logos/blag.txt +17 -0
  73. dripfetch/assets/logos/blankon.txt +17 -0
  74. dripfetch/assets/logos/bluelight.txt +19 -0
  75. dripfetch/assets/logos/bodhi.txt +18 -0
  76. dripfetch/assets/logos/bonsai.txt +16 -0
  77. dripfetch/assets/logos/bredos.txt +9 -0
  78. dripfetch/assets/logos/bsd.txt +19 -0
  79. dripfetch/assets/logos/bunsenlabs.txt +20 -0
  80. dripfetch/assets/logos/cachyos.txt +22 -0
  81. dripfetch/assets/logos/cachyos_small.txt +8 -0
  82. dripfetch/assets/logos/calculate.txt +20 -0
  83. dripfetch/assets/logos/calinixos.txt +25 -0
  84. dripfetch/assets/logos/calinixos_small.txt +15 -0
  85. dripfetch/assets/logos/carbs.txt +18 -0
  86. dripfetch/assets/logos/cbl_mariner.txt +18 -0
  87. dripfetch/assets/logos/celos.txt +15 -0
  88. dripfetch/assets/logos/center.txt +13 -0
  89. dripfetch/assets/logos/centos.txt +19 -0
  90. dripfetch/assets/logos/centos_small.txt +7 -0
  91. dripfetch/assets/logos/cereus.txt +27 -0
  92. dripfetch/assets/logos/chakra.txt +18 -0
  93. dripfetch/assets/logos/chaletos.txt +20 -0
  94. dripfetch/assets/logos/chapeau.txt +18 -0
  95. dripfetch/assets/logos/chimera_linux.txt +18 -0
  96. dripfetch/assets/logos/chonkysealos.txt +21 -0
  97. dripfetch/assets/logos/chrom.txt +18 -0
  98. dripfetch/assets/logos/cleanjaro.txt +12 -0
  99. dripfetch/assets/logos/cleanjaro_small.txt +7 -0
  100. dripfetch/assets/logos/clear_linux.txt +20 -0
  101. dripfetch/assets/logos/clearos.txt +20 -0
  102. dripfetch/assets/logos/clover.txt +20 -0
  103. dripfetch/assets/logos/cobalt.txt +16 -0
  104. dripfetch/assets/logos/codex.txt +12 -0
  105. dripfetch/assets/logos/condres.txt +17 -0
  106. dripfetch/assets/logos/cosmic.txt +11 -0
  107. dripfetch/assets/logos/crux.txt +18 -0
  108. dripfetch/assets/logos/crux_small.txt +7 -0
  109. dripfetch/assets/logos/crystal.txt +20 -0
  110. dripfetch/assets/logos/cucumber.txt +20 -0
  111. dripfetch/assets/logos/cuerdos.txt +13 -0
  112. dripfetch/assets/logos/cutefishos.txt +9 -0
  113. dripfetch/assets/logos/cuteos.txt +14 -0
  114. dripfetch/assets/logos/cyberos.txt +15 -0
  115. dripfetch/assets/logos/cycledream.txt +21 -0
  116. dripfetch/assets/logos/dahlia.txt +17 -0
  117. dripfetch/assets/logos/darkos.txt +20 -0
  118. dripfetch/assets/logos/debian.txt +17 -0
  119. dripfetch/assets/logos/debian_small.txt +6 -0
  120. dripfetch/assets/logos/deepin.txt +18 -0
  121. dripfetch/assets/logos/desaos.txt +16 -0
  122. dripfetch/assets/logos/devuan.txt +15 -0
  123. dripfetch/assets/logos/devuan_small.txt +7 -0
  124. dripfetch/assets/logos/dietpi.txt +19 -0
  125. dripfetch/assets/logos/dracos.txt +13 -0
  126. dripfetch/assets/logos/dragonfly.txt +15 -0
  127. dripfetch/assets/logos/dragonfly_old.txt +17 -0
  128. dripfetch/assets/logos/dragonfly_small.txt +7 -0
  129. dripfetch/assets/logos/drauger.txt +16 -0
  130. dripfetch/assets/logos/droidian.txt +15 -0
  131. dripfetch/assets/logos/elbrus.txt +14 -0
  132. dripfetch/assets/logos/elementary.txt +17 -0
  133. dripfetch/assets/logos/elementary_small.txt +6 -0
  134. dripfetch/assets/logos/elive.txt +17 -0
  135. dripfetch/assets/logos/encryptos.txt +13 -0
  136. dripfetch/assets/logos/endeavouros.txt +15 -0
  137. dripfetch/assets/logos/endeavouros_small.txt +7 -0
  138. dripfetch/assets/logos/endless.txt +20 -0
  139. dripfetch/assets/logos/enso.txt +19 -0
  140. dripfetch/assets/logos/eshanizedos.txt +27 -0
  141. dripfetch/assets/logos/eurolinux.txt +18 -0
  142. dripfetch/assets/logos/evolutionos.txt +21 -0
  143. dripfetch/assets/logos/evolutionos_old.txt +18 -0
  144. dripfetch/assets/logos/evolutionos_small.txt +9 -0
  145. dripfetch/assets/logos/eweos.txt +15 -0
  146. dripfetch/assets/logos/exherbo.txt +22 -0
  147. dripfetch/assets/logos/exodia_predator.txt +24 -0
  148. dripfetch/assets/logos/fastfetch.txt +11 -0
  149. dripfetch/assets/logos/fedora.txt +19 -0
  150. dripfetch/assets/logos/fedora2_small.txt +5 -0
  151. dripfetch/assets/logos/fedora_coreos.txt +20 -0
  152. dripfetch/assets/logos/fedora_kinoite.txt +18 -0
  153. dripfetch/assets/logos/fedora_old.txt +17 -0
  154. dripfetch/assets/logos/fedora_sericea.txt +17 -0
  155. dripfetch/assets/logos/fedora_silverblue.txt +17 -0
  156. dripfetch/assets/logos/fedora_small.txt +9 -0
  157. dripfetch/assets/logos/femboyos.txt +20 -0
  158. dripfetch/assets/logos/feren.txt +16 -0
  159. dripfetch/assets/logos/filotimo.txt +20 -0
  160. dripfetch/assets/logos/finnix.txt +17 -0
  161. dripfetch/assets/logos/floflis.txt +19 -0
  162. dripfetch/assets/logos/freebsd.txt +15 -0
  163. dripfetch/assets/logos/freebsd_small.txt +6 -0
  164. dripfetch/assets/logos/freemint.txt +15 -0
  165. dripfetch/assets/logos/frugalware.txt +23 -0
  166. dripfetch/assets/logos/funtoo.txt +10 -0
  167. dripfetch/assets/logos/furreto.txt +22 -0
  168. dripfetch/assets/logos/galliumos.txt +19 -0
  169. dripfetch/assets/logos/garuda.txt +18 -0
  170. dripfetch/assets/logos/garuda_dragon.txt +24 -0
  171. dripfetch/assets/logos/garuda_small.txt +5 -0
  172. dripfetch/assets/logos/gentoo.txt +18 -0
  173. dripfetch/assets/logos/gentoo_small.txt +7 -0
  174. dripfetch/assets/logos/ghostbsd.txt +13 -0
  175. dripfetch/assets/logos/ghostfreak.txt +19 -0
  176. dripfetch/assets/logos/glaucus.txt +12 -0
  177. dripfetch/assets/logos/gnewsense.txt +12 -0
  178. dripfetch/assets/logos/gnome.txt +21 -0
  179. dripfetch/assets/logos/gnu.txt +18 -0
  180. dripfetch/assets/logos/gobolinux.txt +6 -0
  181. dripfetch/assets/logos/goldendoglinux.txt +19 -0
  182. dripfetch/assets/logos/grapheneos.txt +23 -0
  183. dripfetch/assets/logos/grombyang.txt +18 -0
  184. dripfetch/assets/logos/guix.txt +10 -0
  185. dripfetch/assets/logos/guix_small.txt +7 -0
  186. dripfetch/assets/logos/haiku.txt +12 -0
  187. dripfetch/assets/logos/haiku2.txt +17 -0
  188. dripfetch/assets/logos/haiku_small.txt +8 -0
  189. dripfetch/assets/logos/hamonikr.txt +23 -0
  190. dripfetch/assets/logos/hardclanz.txt +19 -0
  191. dripfetch/assets/logos/harmonyos.txt +19 -0
  192. dripfetch/assets/logos/hash.txt +13 -0
  193. dripfetch/assets/logos/hce.txt +24 -0
  194. dripfetch/assets/logos/heliumos.txt +20 -0
  195. dripfetch/assets/logos/huayra.txt +17 -0
  196. dripfetch/assets/logos/hybrid.txt +16 -0
  197. dripfetch/assets/logos/hydrapwk.txt +11 -0
  198. dripfetch/assets/logos/hydroos.txt +8 -0
  199. dripfetch/assets/logos/hyperbola.txt +16 -0
  200. dripfetch/assets/logos/hyperbola_small.txt +7 -0
  201. dripfetch/assets/logos/hypros.txt +17 -0
  202. dripfetch/assets/logos/iglunix.txt +12 -0
  203. dripfetch/assets/logos/instantos.txt +20 -0
  204. dripfetch/assets/logos/interix.txt +17 -0
  205. dripfetch/assets/logos/irix.txt +19 -0
  206. dripfetch/assets/logos/ironclad.txt +11 -0
  207. dripfetch/assets/logos/itc.txt +10 -0
  208. dripfetch/assets/logos/januslinux.txt +24 -0
  209. dripfetch/assets/logos/kaisen.txt +17 -0
  210. dripfetch/assets/logos/kali.txt +21 -0
  211. dripfetch/assets/logos/kali_small.txt +16 -0
  212. dripfetch/assets/logos/kalpa_desktop.txt +22 -0
  213. dripfetch/assets/logos/kaos.txt +16 -0
  214. dripfetch/assets/logos/kdelinux.txt +14 -0
  215. dripfetch/assets/logos/kdeneon.txt +19 -0
  216. dripfetch/assets/logos/kernelos.txt +19 -0
  217. dripfetch/assets/logos/kibojoe.txt +13 -0
  218. dripfetch/assets/logos/kiss.txt +7 -0
  219. dripfetch/assets/logos/kogaion.txt +20 -0
  220. dripfetch/assets/logos/korora.txt +16 -0
  221. dripfetch/assets/logos/krassos.txt +19 -0
  222. dripfetch/assets/logos/kslinux.txt +11 -0
  223. dripfetch/assets/logos/kubuntu.txt +20 -0
  224. dripfetch/assets/logos/kylin.txt +22 -0
  225. dripfetch/assets/logos/lainos.txt +20 -0
  226. dripfetch/assets/logos/langitketujuh.txt +11 -0
  227. dripfetch/assets/logos/laxeros.txt +20 -0
  228. dripfetch/assets/logos/lede.txt +9 -0
  229. dripfetch/assets/logos/lfs.txt +18 -0
  230. dripfetch/assets/logos/libreelec.txt +20 -0
  231. dripfetch/assets/logos/lilidog.txt +16 -0
  232. dripfetch/assets/logos/lingmo.txt +20 -0
  233. dripfetch/assets/logos/linspire.txt +12 -0
  234. dripfetch/assets/logos/linux.txt +12 -0
  235. dripfetch/assets/logos/linux_small.txt +7 -0
  236. dripfetch/assets/logos/linuxlite.txt +20 -0
  237. dripfetch/assets/logos/linuxlite_small.txt +7 -0
  238. dripfetch/assets/logos/linuxmint.txt +19 -0
  239. dripfetch/assets/logos/linuxmint_old.txt +16 -0
  240. dripfetch/assets/logos/linuxmint_small.txt +7 -0
  241. dripfetch/assets/logos/live_raizo.txt +20 -0
  242. dripfetch/assets/logos/lliurex.txt +16 -0
  243. dripfetch/assets/logos/lmde.txt +17 -0
  244. dripfetch/assets/logos/locos.txt +18 -0
  245. dripfetch/assets/logos/lubuntu.txt +20 -0
  246. dripfetch/assets/logos/lunar.txt +13 -0
  247. dripfetch/assets/logos/macos.txt +17 -0
  248. dripfetch/assets/logos/macos2.txt +17 -0
  249. dripfetch/assets/logos/macos2_small.txt +7 -0
  250. dripfetch/assets/logos/macos3.txt +16 -0
  251. dripfetch/assets/logos/macos_small.txt +7 -0
  252. dripfetch/assets/logos/mageia.txt +19 -0
  253. dripfetch/assets/logos/mageia_small.txt +7 -0
  254. dripfetch/assets/logos/magix.txt +19 -0
  255. dripfetch/assets/logos/magpieos.txt +20 -0
  256. dripfetch/assets/logos/mainsailos.txt +18 -0
  257. dripfetch/assets/logos/mainsailos_small.txt +7 -0
  258. dripfetch/assets/logos/mandriva.txt +15 -0
  259. dripfetch/assets/logos/manjaro.txt +14 -0
  260. dripfetch/assets/logos/manjaro_small.txt +7 -0
  261. dripfetch/assets/logos/massos.txt +18 -0
  262. dripfetch/assets/logos/matuusos.txt +20 -0
  263. dripfetch/assets/logos/maui.txt +20 -0
  264. dripfetch/assets/logos/mauna.txt +15 -0
  265. dripfetch/assets/logos/meowix.txt +10 -0
  266. dripfetch/assets/logos/mer.txt +27 -0
  267. dripfetch/assets/logos/midnightbsd.txt +16 -0
  268. dripfetch/assets/logos/midos.txt +20 -0
  269. dripfetch/assets/logos/midos_old.txt +20 -0
  270. dripfetch/assets/logos/minimal.txt +18 -0
  271. dripfetch/assets/logos/minix.txt +17 -0
  272. dripfetch/assets/logos/miracle_linux.txt +16 -0
  273. dripfetch/assets/logos/mos.txt +18 -0
  274. dripfetch/assets/logos/msys2.txt +25 -0
  275. dripfetch/assets/logos/mx.txt +17 -0
  276. dripfetch/assets/logos/mx2.txt +18 -0
  277. dripfetch/assets/logos/mx_small.txt +7 -0
  278. dripfetch/assets/logos/namib.txt +20 -0
  279. dripfetch/assets/logos/nekos.txt +23 -0
  280. dripfetch/assets/logos/neptune.txt +17 -0
  281. dripfetch/assets/logos/netbsd.txt +17 -0
  282. dripfetch/assets/logos/netbsd2.txt +20 -0
  283. dripfetch/assets/logos/netbsd_small.txt +8 -0
  284. dripfetch/assets/logos/netrunner.txt +20 -0
  285. dripfetch/assets/logos/nexalinux.txt +19 -0
  286. dripfetch/assets/logos/nitrux.txt +18 -0
  287. dripfetch/assets/logos/nixos.txt +20 -0
  288. dripfetch/assets/logos/nixos_old.txt +28 -0
  289. dripfetch/assets/logos/nixos_old_small.txt +7 -0
  290. dripfetch/assets/logos/nixos_small.txt +7 -0
  291. dripfetch/assets/logos/nobara.txt +17 -0
  292. dripfetch/assets/logos/nomadbsd.txt +13 -0
  293. dripfetch/assets/logos/nuros.txt +12 -0
  294. dripfetch/assets/logos/nurunner.txt +19 -0
  295. dripfetch/assets/logos/nutyx.txt +23 -0
  296. dripfetch/assets/logos/obarun.txt +19 -0
  297. dripfetch/assets/logos/obrevenge.txt +18 -0
  298. dripfetch/assets/logos/obsidianos.txt +16 -0
  299. dripfetch/assets/logos/omnios.txt +8 -0
  300. dripfetch/assets/logos/opak.txt +13 -0
  301. dripfetch/assets/logos/openbsd.txt +23 -0
  302. dripfetch/assets/logos/openbsd_small.txt +7 -0
  303. dripfetch/assets/logos/openeuler.txt +23 -0
  304. dripfetch/assets/logos/openindiana.txt +16 -0
  305. dripfetch/assets/logos/openkylin.txt +18 -0
  306. dripfetch/assets/logos/openmamba.txt +21 -0
  307. dripfetch/assets/logos/openmandriva.txt +22 -0
  308. dripfetch/assets/logos/openstage.txt +17 -0
  309. dripfetch/assets/logos/opensuse.txt +18 -0
  310. dripfetch/assets/logos/opensuse_leap.txt +18 -0
  311. dripfetch/assets/logos/opensuse_leap_old.txt +16 -0
  312. dripfetch/assets/logos/opensuse_microos.txt +10 -0
  313. dripfetch/assets/logos/opensuse_slowroll.txt +20 -0
  314. dripfetch/assets/logos/opensuse_small.txt +7 -0
  315. dripfetch/assets/logos/opensuse_tumbleweed.txt +22 -0
  316. dripfetch/assets/logos/opensuse_tumbleweed_old.txt +13 -0
  317. dripfetch/assets/logos/opensuse_tumbleweed_small.txt +9 -0
  318. dripfetch/assets/logos/openwrt.txt +9 -0
  319. dripfetch/assets/logos/opnsense.txt +20 -0
  320. dripfetch/assets/logos/oracle.txt +11 -0
  321. dripfetch/assets/logos/orchid.txt +20 -0
  322. dripfetch/assets/logos/orchid_small.txt +13 -0
  323. dripfetch/assets/logos/oreon.txt +22 -0
  324. dripfetch/assets/logos/os_elbrus.txt +14 -0
  325. dripfetch/assets/logos/osmc.txt +20 -0
  326. dripfetch/assets/logos/pacbsd.txt +24 -0
  327. dripfetch/assets/logos/panwah.txt +21 -0
  328. dripfetch/assets/logos/parabola.txt +16 -0
  329. dripfetch/assets/logos/parabola_small.txt +6 -0
  330. dripfetch/assets/logos/parch.txt +25 -0
  331. dripfetch/assets/logos/pardus.txt +18 -0
  332. dripfetch/assets/logos/parrot.txt +24 -0
  333. dripfetch/assets/logos/parsix.txt +21 -0
  334. dripfetch/assets/logos/pcbsd.txt +27 -0
  335. dripfetch/assets/logos/pclinuxos.txt +19 -0
  336. dripfetch/assets/logos/pearos.txt +21 -0
  337. dripfetch/assets/logos/pengwin.txt +15 -0
  338. dripfetch/assets/logos/pentoo.txt +20 -0
  339. dripfetch/assets/logos/peppermint.txt +21 -0
  340. dripfetch/assets/logos/peropesis.txt +5 -0
  341. dripfetch/assets/logos/phyos.txt +17 -0
  342. dripfetch/assets/logos/pikaos.txt +18 -0
  343. dripfetch/assets/logos/pisi.txt +19 -0
  344. dripfetch/assets/logos/pnm_linux.txt +19 -0
  345. dripfetch/assets/logos/pop.txt +20 -0
  346. dripfetch/assets/logos/pop_small.txt +8 -0
  347. dripfetch/assets/logos/porteus.txt +23 -0
  348. dripfetch/assets/logos/postmarketos.txt +18 -0
  349. dripfetch/assets/logos/postmarketos_small.txt +9 -0
  350. dripfetch/assets/logos/proxmox.txt +20 -0
  351. dripfetch/assets/logos/puffos.txt +12 -0
  352. dripfetch/assets/logos/puppy.txt +18 -0
  353. dripfetch/assets/logos/pureos.txt +12 -0
  354. dripfetch/assets/logos/pureos_small.txt +6 -0
  355. dripfetch/assets/logos/q4os.txt +19 -0
  356. dripfetch/assets/logos/qts.txt +14 -0
  357. dripfetch/assets/logos/qubes.txt +21 -0
  358. dripfetch/assets/logos/qubyt.txt +15 -0
  359. dripfetch/assets/logos/quibian.txt +18 -0
  360. dripfetch/assets/logos/quirinux.txt +17 -0
  361. dripfetch/assets/logos/radix.txt +18 -0
  362. dripfetch/assets/logos/raspbian.txt +23 -0
  363. dripfetch/assets/logos/raspbian_small.txt +10 -0
  364. dripfetch/assets/logos/ravynos.txt +20 -0
  365. dripfetch/assets/logos/rebornos.txt +20 -0
  366. dripfetch/assets/logos/rebornos_small.txt +7 -0
  367. dripfetch/assets/logos/redcore.txt +16 -0
  368. dripfetch/assets/logos/redos.txt +18 -0
  369. dripfetch/assets/logos/redos_small.txt +8 -0
  370. dripfetch/assets/logos/redstar.txt +18 -0
  371. dripfetch/assets/logos/refracted_devuan.txt +18 -0
  372. dripfetch/assets/logos/regata.txt +20 -0
  373. dripfetch/assets/logos/regolith.txt +18 -0
  374. dripfetch/assets/logos/rhaymos.txt +14 -0
  375. dripfetch/assets/logos/rhel.txt +18 -0
  376. dripfetch/assets/logos/rhel_old.txt +16 -0
  377. dripfetch/assets/logos/rhel_small.txt +9 -0
  378. dripfetch/assets/logos/rhino.txt +12 -0
  379. dripfetch/assets/logos/rocky.txt +19 -0
  380. dripfetch/assets/logos/rocky_small.txt +12 -0
  381. dripfetch/assets/logos/rosa.txt +18 -0
  382. dripfetch/assets/logos/sabayon.txt +18 -0
  383. dripfetch/assets/logos/sabotage.txt +11 -0
  384. dripfetch/assets/logos/sailfish.txt +13 -0
  385. dripfetch/assets/logos/salentos.txt +20 -0
  386. dripfetch/assets/logos/salientos.txt +20 -0
  387. dripfetch/assets/logos/salix.txt +18 -0
  388. dripfetch/assets/logos/sambabox.txt +19 -0
  389. dripfetch/assets/logos/sasanqua.txt +18 -0
  390. dripfetch/assets/logos/scientific.txt +20 -0
  391. dripfetch/assets/logos/semc.txt +9 -0
  392. dripfetch/assets/logos/septor.txt +20 -0
  393. dripfetch/assets/logos/serene.txt +20 -0
  394. dripfetch/assets/logos/serpent_os.txt +18 -0
  395. dripfetch/assets/logos/sharklinux.txt +15 -0
  396. dripfetch/assets/logos/shastraos.txt +19 -0
  397. dripfetch/assets/logos/shebang.txt +20 -0
  398. dripfetch/assets/logos/siduction.txt +20 -0
  399. dripfetch/assets/logos/skiffos.txt +9 -0
  400. dripfetch/assets/logos/slackel.txt +22 -0
  401. dripfetch/assets/logos/slackware.txt +21 -0
  402. dripfetch/assets/logos/slackware_small.txt +7 -0
  403. dripfetch/assets/logos/sleeperos.txt +16 -0
  404. dripfetch/assets/logos/sleeperos_small.txt +7 -0
  405. dripfetch/assets/logos/slitaz.txt +17 -0
  406. dripfetch/assets/logos/smartos.txt +17 -0
  407. dripfetch/assets/logos/snigdhaos.txt +20 -0
  408. dripfetch/assets/logos/soda.txt +15 -0
  409. dripfetch/assets/logos/solaris.txt +8 -0
  410. dripfetch/assets/logos/solaris_small.txt +5 -0
  411. dripfetch/assets/logos/solus.txt +20 -0
  412. dripfetch/assets/logos/source_mage.txt +21 -0
  413. dripfetch/assets/logos/sparky.txt +20 -0
  414. dripfetch/assets/logos/spoinkos.txt +5 -0
  415. dripfetch/assets/logos/star.txt +19 -0
  416. dripfetch/assets/logos/steamdeck.txt +24 -0
  417. dripfetch/assets/logos/steamdeck_small.txt +5 -0
  418. dripfetch/assets/logos/steamos.txt +18 -0
  419. dripfetch/assets/logos/stock_linux.txt +19 -0
  420. dripfetch/assets/logos/sulin.txt +20 -0
  421. dripfetch/assets/logos/summitos.txt +22 -0
  422. dripfetch/assets/logos/suse.txt +11 -0
  423. dripfetch/assets/logos/swagarch.txt +15 -0
  424. dripfetch/assets/logos/t2.txt +14 -0
  425. dripfetch/assets/logos/t2_small.txt +6 -0
  426. dripfetch/assets/logos/tails.txt +19 -0
  427. dripfetch/assets/logos/tatra.txt +15 -0
  428. dripfetch/assets/logos/tearch.txt +21 -0
  429. dripfetch/assets/logos/templeos.txt +20 -0
  430. dripfetch/assets/logos/tileos.txt +20 -0
  431. dripfetch/assets/logos/torizoncore.txt +29 -0
  432. dripfetch/assets/logos/trisquel.txt +17 -0
  433. dripfetch/assets/logos/truenas_scale.txt +18 -0
  434. dripfetch/assets/logos/tuxedo_os.txt +16 -0
  435. dripfetch/assets/logos/twister.txt +23 -0
  436. dripfetch/assets/logos/ublinux.txt +19 -0
  437. dripfetch/assets/logos/ublinux_small.txt +11 -0
  438. dripfetch/assets/logos/ubuntu.txt +20 -0
  439. dripfetch/assets/logos/ubuntu_budgie.txt +20 -0
  440. dripfetch/assets/logos/ubuntu_cinnamon.txt +20 -0
  441. dripfetch/assets/logos/ubuntu_gnome.txt +16 -0
  442. dripfetch/assets/logos/ubuntu_kylin.txt +20 -0
  443. dripfetch/assets/logos/ubuntu_mate.txt +20 -0
  444. dripfetch/assets/logos/ubuntu_old.txt +20 -0
  445. dripfetch/assets/logos/ubuntu_old2.txt +18 -0
  446. dripfetch/assets/logos/ubuntu_old2_small.txt +6 -0
  447. dripfetch/assets/logos/ubuntu_small.txt +11 -0
  448. dripfetch/assets/logos/ubuntu_studio.txt +20 -0
  449. dripfetch/assets/logos/ubuntu_sway.txt +20 -0
  450. dripfetch/assets/logos/ubuntu_touch.txt +7 -0
  451. dripfetch/assets/logos/ubuntu_unity.txt +25 -0
  452. dripfetch/assets/logos/ultramarine.txt +20 -0
  453. dripfetch/assets/logos/ultramarine_small.txt +14 -0
  454. dripfetch/assets/logos/unifi.txt +6 -0
  455. dripfetch/assets/logos/univalent.txt +18 -0
  456. dripfetch/assets/logos/univention.txt +20 -0
  457. dripfetch/assets/logos/unknown.txt +18 -0
  458. dripfetch/assets/logos/uos.txt +20 -0
  459. dripfetch/assets/logos/urukos.txt +20 -0
  460. dripfetch/assets/logos/uwuntu.txt +20 -0
  461. dripfetch/assets/logos/valhalla.txt +10 -0
  462. dripfetch/assets/logos/vanilla.txt +18 -0
  463. dripfetch/assets/logos/vanilla2.txt +16 -0
  464. dripfetch/assets/logos/vanilla_small.txt +7 -0
  465. dripfetch/assets/logos/venom.txt +19 -0
  466. dripfetch/assets/logos/venom_small.txt +11 -0
  467. dripfetch/assets/logos/vnux.txt +20 -0
  468. dripfetch/assets/logos/void.txt +18 -0
  469. dripfetch/assets/logos/void2.txt +25 -0
  470. dripfetch/assets/logos/void2_small.txt +7 -0
  471. dripfetch/assets/logos/void_small.txt +7 -0
  472. dripfetch/assets/logos/vzlinux.txt +20 -0
  473. dripfetch/assets/logos/wii_linux.txt +16 -0
  474. dripfetch/assets/logos/windows.txt +16 -0
  475. dripfetch/assets/logos/windows_11.txt +17 -0
  476. dripfetch/assets/logos/windows_11_small.txt +7 -0
  477. dripfetch/assets/logos/windows_2025.txt +17 -0
  478. dripfetch/assets/logos/windows_8.txt +19 -0
  479. dripfetch/assets/logos/windows_95.txt +18 -0
  480. dripfetch/assets/logos/wolfos.txt +5 -0
  481. dripfetch/assets/logos/xcp_ng.txt +15 -0
  482. dripfetch/assets/logos/xenia.txt +15 -0
  483. dripfetch/assets/logos/xenia_old.txt +21 -0
  484. dripfetch/assets/logos/xeroarch.txt +19 -0
  485. dripfetch/assets/logos/xferience.txt +19 -0
  486. dripfetch/assets/logos/xray_os.txt +21 -0
  487. dripfetch/assets/logos/xubuntu.txt +19 -0
  488. dripfetch/assets/logos/yiffos.txt +19 -0
  489. dripfetch/assets/logos/zorin.txt +17 -0
  490. dripfetch/assets/logos/zos.txt +7 -0
  491. dripfetch/box/__init__.py +5 -0
  492. dripfetch/box/base.py +24 -0
  493. dripfetch/box/borders.py +41 -0
  494. dripfetch/box/colors.py +110 -0
  495. dripfetch/box/manager.py +181 -0
  496. dripfetch/box/placement.py +40 -0
  497. dripfetch/box/types/__init__.py +5 -0
  498. dripfetch/box/types/clock.py +487 -0
  499. dripfetch/box/types/logo.py +62 -0
  500. dripfetch/box/types/sysinfo.py +570 -0
  501. dripfetch/box/types/text.py +16 -0
  502. dripfetch/box/types/weather.py +181 -0
  503. dripfetch/cli.py +58 -0
  504. dripfetch/config.py +405 -0
  505. dripfetch/default_config.yaml +80 -0
  506. dripfetch/rain/__init__.py +3 -0
  507. dripfetch/rain/collision.py +23 -0
  508. dripfetch/rain/colors.py +51 -0
  509. dripfetch/rain/drop.py +16 -0
  510. dripfetch/rain/engine.py +190 -0
  511. dripfetch/rain/movement.py +46 -0
  512. dripfetch/rain/spawning.py +59 -0
  513. dripfetch/terminal.py +193 -0
  514. dripfetch-0.1.0.dist-info/METADATA +47 -0
  515. dripfetch-0.1.0.dist-info/RECORD +519 -0
  516. dripfetch-0.1.0.dist-info/WHEEL +5 -0
  517. dripfetch-0.1.0.dist-info/entry_points.txt +2 -0
  518. dripfetch-0.1.0.dist-info/licenses/LICENSE +21 -0
  519. 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
+ )