Commit e0aadec964
Verified · cmc
Layout: unified · split
content/blog/2026-08-20-nfogen.org +150 −51
| @@ -18,51 +18,56 @@ credits, installation instructions, BBS/contact info, greetz/notes, etc. | |||
| 18 | For example, here's the =bonzai.nfo= file for a patched save game for Lemmings | 18 | For example, here's the =bonzai.nfo= file for a patched save game for Lemmings |
| 19 | III, with credits to those involved and instructions to get in touch. | 19 | III, with credits to those involved and instructions to get in touch. |
| 20 | 20 | ||
| 21 | /Note: The [[http://www.textfiles.com/piracy/NFO/bonzai.nfo][original file]] on textfiles.com contains CP437 bytes decoded as | ||
| 22 | Cyrillic, so I converted this example correctly to CP437. If you view the online | ||
| 23 | version, you'll notice that the box drawing and group logo are incomprehensible, | ||
| 24 | which proves my point later on in the CP437 section./ | ||
| 25 | |||
| 21 | #+begin_src nfo | 26 | #+begin_src nfo |
| 22 | К К | 27 | ║ ║ |
| 23 | 28 | ||
| 24 | лллллК К | 29 | █████║ ║ |
| 25 | лллллК К | 30 | █████║ ║ |
| 26 | лллллпллл лллллпллл лллллпллл лллллпллл лллллпллл ппппп | 31 | █████▀███ █████▀███ █████▀███ █████▀███ █████▀███ ▀▀▀▀▀ |
| 27 | лллллКлллл ллллл лллл ллллл лллл ллллл лллл ллллл лллл ллллл | 32 | █████║████ █████ ████ █████ ████ █████ ████ █████ ████ █████ |
| 28 | лллллКлллл ллллл лллл ллллл лллл ммммммлллл лллллмлллл лллллл | 33 | █████║████ █████ ████ █████ ████ ▄▄▄▄▄▄████ █████▄████ ██████ |
| 29 | лллллКлллл ллллл лллл ллллл лллл ллллл мммм ллллл лллл лллллл | 34 | █████║████ █████ ████ █████ ████ █████ ▄▄▄▄ █████ ████ ██████ |
| 30 | ллллл лллл ллллл лллл ллллл лллл ллллл лллл ллллл лллл лллллл | 35 | █████ ████ █████ ████ █████ ████ █████ ████ █████ ████ ██████ |
| 31 | лллллКлллл ллллл лллл ллллл лллл ллллл лллл ллллл лллл лллллл | 36 | █████║████ █████ ████ █████ ████ █████ ████ █████ ████ ██████ |
| 32 | лллллКлллл ллллл лллл ллллл лллл ллллл лллл ллллл лллл лллллл | 37 | █████║████ █████ ████ █████ ████ █████ ████ █████ ████ ██████ |
| 33 | ллллл лллл ллллл лллл ллллл лллл ллллл лллл ллллл лллл лллллл | 38 | █████ ████ █████ ████ █████ ████ █████ ████ █████ ████ ██████ |
| 34 | пппппппппп пппппппппп ппппп пппп пппппппппп ппппп пппп пппппп | 39 | ▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀ ▀▀▀▀ ▀▀▀▀▀▀▀▀▀▀ ▀▀▀▀▀ ▀▀▀▀ ▀▀▀▀▀▀ |
| 35 | К жФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФЗ К | 40 | ║ ╓────────────────────────────────────────╖ ║ |
| 36 | К ў BONZAi Ф EVERYTHiNG BUT FRiENDSHiP ў К | 41 | ║ ■ BONZAi ─ EVERYTHiNG BUT FRiENDSHiP ■ ║ |
| 37 | К гФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФФН К | 42 | ║ ╙────────────────────────────────────────╜ ║ |
| 38 | R E L E A S E D : | 43 | R E L E A S E D : |
| 39 | К К | 44 | ║ ║ |
| 40 | К 9O BYTES SAVE GAME PATCHER FOR LEMMiNGS III К | 45 | ║ 9O BYTES SAVE GAME PATCHER FOR LEMMiNGS III ║ |
| 41 | 46 | ||
| 42 | К FiLENAME .............. : ........... BNZ-L3T.ZiP К | 47 | ║ FiLENAME .............. : ........... BNZ-L3T.ZiP ║ |
| 43 | К TYPE .................. : ............... TRAiNER К | 48 | ║ TYPE .................. : ............... TRAiNER ║ |
| 44 | К COMPANY ............... : ............. PSYGNOSiS К | 49 | ║ COMPANY ............... : ............. PSYGNOSiS ║ |
| 45 | К CODER .. .............. : ................ SCAMPY К | 50 | ║ CODER .. .............. : ................ SCAMPY ║ |
| 46 | К PACKAGER .............. : ................ SCAMPY К | 51 | ║ PACKAGER .............. : ................ SCAMPY ║ |
| 47 | К DATE AT RELEASiNG ..... : ............ 11-27-1994 К | 52 | ║ DATE AT RELEASiNG ..... : ............ 11-27-1994 ║ |
| 48 | К TiME AT RELEASiNG ..... : .............. 15:OO PM К | 53 | ║ TiME AT RELEASiNG ..... : .............. 15:OO PM ║ |
| 49 | К RELEASE NOTES : ..................... READ BELOW! К | 54 | ║ RELEASE NOTES : ..................... READ BELOW! ║ |
| 50 | К К | 55 | ║ ║ |
| 51 | К !!!*!!! IMPORTANT !!!*!!! К | 56 | ║ !!!*!!! IMPORTANT !!!*!!! ║ |
| 52 | К К | 57 | ║ ║ |
| 53 | К NiCE PATCHER FOR A NiCE GAME - THiS PATCHER WAS К | 58 | ║ NiCE PATCHER FOR A NiCE GAME - THiS PATCHER WAS ║ |
| 54 | К KINDA DiFFiCULT BECAUSE OF THE MANY BYTES TO BE К | 59 | ║ KINDA DiFFiCULT BECAUSE OF THE MANY BYTES TO BE ║ |
| 55 | К PATCHED. BUT PROBLEMS WiTH PATCHiNG TiME AND К | 60 | ║ PATCHED. BUT PROBLEMS WiTH PATCHiNG TiME AND ║ |
| 56 | К FiLE LENGTH HAVE BEEN SOLVED. К | 61 | ║ FiLE LENGTH HAVE BEEN SOLVED. ║ |
| 57 | К К | 62 | ║ ║ |
| 58 | К ENJOY PLAYiN' -SCAMPY! К | 63 | ║ ENJOY PLAYiN' -SCAMPY! ║ |
| 59 | К К | 64 | ║ ║ |
| 60 | К К | 65 | ║ ║ |
| 61 | К MEMBERS OF BONZAi ARE . : К | 66 | ║ MEMBERS OF BONZAi ARE . : ║ |
| 62 | К MOTiV8- SCAMPY- SUM-1- DEViL К | 67 | ║ MOTiV8- SCAMPY- SUM-1- DEViL ║ |
| 63 | К К | 68 | ║ ║ |
| 64 | К BULLETiN BOARD SYSTEMS : К | 69 | ║ BULLETiN BOARD SYSTEMS : ║ |
| 65 | Э Э ЭЭ ЭЭЭМ NONE! SEARCHiNG! ШЭЭЭ ЭЭ Э Э | 70 | ═ ═ ══ ═══╝ NONE! SEARCHiNG! ╚═══ ══ ═ ═ |
| 66 | 71 | ||
| 67 | GREETiNGS TO: | 72 | GREETiNGS TO: |
| 68 | TOXiC HYBRiD PENTAGRAM PARADOX THHG G.T.A TRSI | 73 | TOXiC HYBRiD PENTAGRAM PARADOX THHG G.T.A TRSI |
| @@ -72,7 +77,7 @@ III, with credits to those involved and instructions to get in touch. | |||
| 72 | CURRENTLY WE ARE SEARCHiNG FOR ALL KiND OF MEMBERS.. LiKE TRADERS | 77 | CURRENTLY WE ARE SEARCHiNG FOR ALL KiND OF MEMBERS.. LiKE TRADERS |
| 73 | SUPPLiERS.. SYSOPS.. ETC. | 78 | SUPPLiERS.. SYSOPS.. ETC. |
| 74 | 79 | ||
| 75 | Э Э ЭЭ ЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭЭ ЭЭ Э Э | 80 | ═ ═ ══ ══════════════════════════════════════════════════════════ ══ ═ ═ |
| 76 | #+end_src | 81 | #+end_src |
| 77 | 82 | ||
| 78 | If you want to browse an archive of NFO files, head over to [[http://www.textfiles.com/piracy/NFO/][textfiles]]. | 83 | If you want to browse an archive of NFO files, head over to [[http://www.textfiles.com/piracy/NFO/][textfiles]]. |
| @@ -95,7 +100,7 @@ use code blocks, like I did above). | |||
| 95 | One such character set was often used for NFO files: IBM's [[https://en.wikipedia.org/wiki/Code_page_437][CP437]] character set, | 100 | One such character set was often used for NFO files: IBM's [[https://en.wikipedia.org/wiki/Code_page_437][CP437]] character set, |
| 96 | released with the 1981 IBM PC. This set was popular because each character could | 101 | released with the 1981 IBM PC. This set was popular because each character could |
| 97 | be typed with an alt code in DOS, even if they were not on the user's keyboard. | 102 | be typed with an alt code in DOS, even if they were not on the user's keyboard. |
| 98 | E.g., =Alt + 2665= would result in the following character: =♥=. | 103 | E.g., =Alt + 3= would result in the following character: =♥=. |
| 99 | 104 | ||
| 100 | * Introducing: nfogen | 105 | * Introducing: nfogen |
| 101 | 106 | ||
| @@ -104,7 +109,8 @@ recently. As part of this, I started using NFO files for my git repos under my | |||
| 104 | new org and wanted a tool that could help me accelerate the generation of these | 109 | new org and wanted a tool that could help me accelerate the generation of these |
| 105 | files. | 110 | files. |
| 106 | 111 | ||
| 107 | Introducing [[https://github.com/krazywarez/nfogen][nfogen]], a small Python utility that can generate NFO files for you based on: | 112 | Introducing [[https://github.com/krazywarez/nfogen][nfogen]], a small Python utility that can generate NFO files for you |
| 113 | based on: | ||
| 108 | - templates | 114 | - templates |
| 109 | - profiles | 115 | - profiles |
| 110 | - configuration files | 116 | - configuration files |
| @@ -172,7 +178,7 @@ generated by nfogen: nfogen.py -c nfogen.toml | |||
| 172 | Next, I ran the following command, which produced the NFO file below: | 178 | Next, I ran the following command, which produced the NFO file below: |
| 173 | 179 | ||
| 174 | #+begin_src shell | 180 | #+begin_src shell |
| 175 | nfogen.py -c nfogen.toml -p -o README.nfo | 181 | nfogen.py -c nfogen.toml -o README.nfo |
| 176 | #+end_src | 182 | #+end_src |
| 177 | 183 | ||
| 178 | #+begin_src nfo | 184 | #+begin_src nfo |
| @@ -230,12 +236,11 @@ For more examples, browse the [[https://github.com/krazywarez/nfogen/tree/main/e | |||
| 230 | * Usage | 236 | * Usage |
| 231 | ** Installation | 237 | ** Installation |
| 232 | 238 | ||
| 233 | The fastest installation method is to clone the repo and use the Python file | 239 | The fastest installation method is to fetch and use the Python file directly: |
| 234 | directly: | ||
| 235 | 240 | ||
| 236 | #+begin_src shell | 241 | #+begin_src shell |
| 237 | git clone https://github.com/krazywarez/nfogen.git && cd nfogen | 242 | curl -O https://raw.githubusercontent.com/krazywarez/nfogen/main/nfogen.py |
| 238 | nfogen.py -i | 243 | python3 nfogen.py -i |
| 239 | #+end_src | 244 | #+end_src |
| 240 | 245 | ||
| 241 | ** Generating a File | 246 | ** Generating a File |
| @@ -262,9 +267,103 @@ nfogen itself works by parsing the various inputs, determining a style to use | |||
| 262 | for the box-drawing/character sets, and rendering the characters individually by | 267 | for the box-drawing/character sets, and rendering the characters individually by |
| 263 | rows and columns. | 268 | rows and columns. |
| 264 | 269 | ||
| 270 | ** Width | ||
| 271 | |||
| 272 | The first issue I ran into was determining the width to use. I settled on 79 | ||
| 273 | characters, with border characters at both ends, because X. This means that my | ||
| 274 | script needs to perform some math to calculate wrapping, padding, and centering | ||
| 275 | of text throughout. | ||
| 276 | |||
| 277 | The math is relatively simple because CP437 is single-byte and single-width, | ||
| 278 | which means I can write functions that depend on that one-to-one correlation | ||
| 279 | to calculate the spacing properly. | ||
| 280 | |||
| 281 | =_Canvas.__init__= defines a few key variables for width: | ||
| 282 | |||
| 283 | #+begin_src python | ||
| 284 | self.width = width | ||
| 285 | self.inner = width - 4 # single-column content width | ||
| 286 | self.cl = (width - 7) // 2 # left panel content width | ||
| 287 | self.cr = (width - 7) - self.cl | ||
| 288 | self.rfill = width - self.cl - 5 | ||
| 289 | #+end_src | ||
| 290 | |||
| 291 | At a width of 79 characters, this breaks down into: | ||
| 292 | |||
| 293 | | Variable | Value | What it covers | | ||
| 294 | |------------+-------+---------------------------------------------------------| | ||
| 295 | | =self.width= | 79 | Total line width, borders included | | ||
| 296 | | =self.inner= | 75 | Single-column content, minus two verticals and two pads | | ||
| 297 | | =self.cl= | 36 | Left panel content width | | ||
| 298 | | =self.cr= | 36 | Right panel content, taking the remainder | | ||
| 299 | | =self.rfill= | 38 | Rule segment right of the joint, =cr= plus its two pads | | ||
| 300 | |||
| 301 | These combine into a cohesive 79-chararacter-width NFO file with consistent | ||
| 302 | padding and alignment. | ||
| 303 | |||
| 304 | ** Character Sets | ||
| 305 | |||
| 306 | =nfogen= currently supports two different character sets as outputs: UTF-8 and | ||
| 307 | CP437. For example, there are =╔ ═ ║= characters in the UTF-8 example, but a real | ||
| 308 | CP437 file contains the single bytes =0xC9 0xCD 0xBA=. | ||
| 309 | |||
| 310 | However, this doesn't really change the core generation of the NFO file. The | ||
| 311 | file itself is charset-independent and the charset only comes into play during | ||
| 312 | the final encode of the file. | ||
| 313 | |||
| 314 | Referring back to the =bonzai.nfo= file above, it was decoded improperly as | ||
| 315 | ISO-8859-5, which resulted in Cyrillic characters instead of the proper charset. | ||
| 316 | Defining an appropriate charset and encoding/decoding is critical to ensuring | ||
| 317 | the longevity of NFO files. | ||
| 318 | |||
| 319 | ** Banner Generator | ||
| 320 | |||
| 321 | The banner generator is a function by itself, which renders independent from the | ||
| 322 | rest of the file and separate from the box geometry. This function defines a set | ||
| 323 | of glyphs, takes an input text string from the user, and maps each character to | ||
| 324 | its glyph. The result is rendered above the box and is centered, so it does not | ||
| 325 | depend on the math applied to the canvas. | ||
| 326 | |||
| 327 | If an explicity art file is defined, this generator does not run. | ||
| 328 | |||
| 329 | #+begin_src python | ||
| 330 | # A compact 5-row block font for the banner generator. Each glyph is five | ||
| 331 | # rows joined by "/". Uppercase letters, digits, space, and [<35;44;2Ma few symbols. | ||
| 332 | _FONT = { | ||
| 333 | "A": " ### /# #/#####/# #/# #", "B": "#### /# #/#### /# #/#### ", | ||
| 334 | "C": " ####/# /# /# / ####", "D": "#### /# #/# #/# #/#### ", | ||
| 335 | # ... through Z, 0-9, space, -, ., !, : | ||
| 336 | } | ||
| 337 | |||
| 338 | |||
| 339 | def banner(text: str) -> str: | ||
| 340 | """Render text as a 5-row ASCII banner using the built-in block font.""" | ||
| 341 | rows = ["", "", "", "", ""] | ||
| 342 | for ch in text.upper(): | ||
| 343 | glyph = _FONT.get(ch, _FONT[" "]).split("/") | ||
| 344 | for i in range(5): | ||
| 345 | rows[i] += glyph[i] + " " | ||
| 346 | return "\n".join(r.rstrip() for r in rows) | ||
| 347 | #+end_src | ||
| 348 | |||
| 349 | ** Resolution Order | ||
| 350 | |||
| 351 | Finally, I defined a specific order to the inputs. As stated in the README, the | ||
| 352 | order of importance is: =template < profile < config file < CLI flags < prompts=. | ||
| 353 | |||
| 354 | This was an opinionated design choice, as I felt that if you were to create a | ||
| 355 | template, that should take precedence above all. Then, profiles and | ||
| 356 | configurations are additional preconfigured files that require effort to create | ||
| 357 | and maintain, which earns them the next spots. Finally, the script falls back to | ||
| 358 | CLI arguments, if supplied, and then interactive prompt mode if nothing else | ||
| 359 | exists. | ||
| 360 | |||
| 265 | * The Future | 361 | * The Future |
| 266 | 362 | ||
| 267 | I'd love to build this tool out to support more character sets, pre-built | 363 | I'd love to build this tool out to support more character sets, pre-built |
| 268 | libraries for ASCII art and table layouts, and more customization options. | 364 | libraries for ASCII art and table layouts, and more customization options. |
| 269 | 365 | ||
| 366 | For now, the tool works and is sufficient for my personal use cases, so I'm | ||
| 367 | content with it. | ||
| 368 | |||
| 270 | If you're interested in helping, feel free to reach out! | 369 | If you're interested in helping, feel free to reach out! |