Béton brut

In Terminal Veritas

2022-03-30

TL;DR: wszystkie teksty na stronie można czytać na terminalu przy użyciu curla:

curl -s https://fuse.pl/beton/cegla.html | less
curl -s https://fuse.pl/beton/focu.sh.html | less

Jestem dinozaurem (technologii): potężny, kochany przez dzieci i dorosłych, źródło strachu i fascynacji, a także inspiracji. Prawdopodobnie nigdy nie porzucę idei, że klawiatura i terminal są najbardziej efektywną metodą komunikowania myśli i celów komputerowi.

Czasem zadaję sobie pytanie, czy lubię tak żyć dlatego, że potrafię tak żyć, czy też w drugą stronę — nauczyłem się tak żyć dlatego, że lubiłem tak żyć. Wydaje mi się, że fascynacja poprzedza komfort, a jeśli uda się tę fascynację utrzymać, to wszystko równoważy się w jakiś sposób, który trudno wytłumaczyć bez odwoływania się do ontologii.

Ponieważ wszystko nadal mnie bawi, uwielbiam budować różne pierdoły, karykatury prawdziwych technologii na marginesach notatników, bezużyteczne dla większości ludzi.

Dla przykładu: pomiędzy dwiema połowami piłkarskiego meczu odbywa się spektakl obrzydliwości zwany «studiem», w którym różni ludzie mówią o meczu, jak gdybym go przed chwilą nie doświadczył na własne oczy. To wszystko jest wsadzone między dwie kromki reklam. Piętnaście minut żenady. Wystrugałem sobie więc stfufor, który przyjmuje minuty jako parametr. Połączenie catt i at ścisza transmisję, a następnie podbija głośność nazad po zadanym czasie. Kiedy słyszę gwizdek kończący połowę, piszę po prostu stfufor 15.

Mój bojler wyłącza się, kiedy wychodzę z domu. Nie muszę o tym informować jakiegoś chińskiego operatora chmury, żeby łaskawie wydał callback do mojego gniazdka, RPi ma listę urządzeń i na podstawie arpinga stwierdza, że albo mnie nie ma, albo śpię — w każdym razie zmywanie raczej nie jest wysoko na liście priorytetów. Za każdym razem, gdy wracam do domu, słyszę po kilku minutach «klik» przekaźnika i uśmiecham się do siebie jak poskramiacz cherlawych lwów: dumny, choć świadomy braku po temu powodu.

Kilka lat temu przez social media przeleciał projekt tego rodzaju, serwis wyświetlający prognozę pogody na terminalu. Pobawiłem się, było to bardzo ładne, cudo technologicznego kiczu. Nie analizowałem jednak detali — być może jestem nadal pod wpływem traumy, gdy pokazałem jakiś „sprawdzacz pogody” mojemu ówczesnemu administratorowi, na którego serwerze gościłem. Powiedział: „opi, a nie możesz kurwa wyjrzeć za okno?”. Do dziś nie znalazłem odpowiedzi na takie dictum.


Sam jednak pomysł wydał mi się całkiem ciekawy, szczególnie ze względu na pewien dualizm: serwis działał tak samo w przeglądarce i terminalu. Postanowiłem odtworzyć ten efekt, przystosowując stronę, którą czytasz, do podobnego działania.

Pierwsze, co należało ustalić, to czy curl, który domyślnie wyświetla pobrane informacje na stdio, zachowuje wszystkie style, kiedy pobiera plik tekstowy z serwera HTTP. Stworzyłem przykładowy plik z testowymi formatowaniami: pogrubienie, czerwony kolor etc., po czym odpaliłem webfsd, mikro-serwer statycznych treści. Wszystko poszło bez problemu, połowa drogi przebyta.

Teraz trudniejsze pytanie: w jaki sposób odbywa się negocjacja treści? Wczytanie URI w przeglądarce i przez curl pokazuje HTML i tekst. Przeglądarka może negocjować za pomocą nagłówków, w przypadku curl musimy polegać na tym, co jest domyślnie wysyłane do serwera. Poszedłem tropem podglądania user-agent. Dodałem -A "Przeglądarka" do wywołania… i wrócił HTML. Aha, czyli pierwszy strzał od razu celny.

Dopisałem do konfiguracji nginx testową linijkę, która przekierowywałaby do dokumentu stworzonego wcześniej. Jeśli wszystko zadziała, to gdy robię curl https://fuse.pl/beton/cegla.html, powinienem zostać zawrócony, a na ekranie wyświetli się sformatowany plik.

Część logistyczno-infrastrukturalna rozwiązana. Co z treścią? Teksty źródłowe mam w „utylitarnym markdownie”: wszystko, co jest wygodne i praktyczne, jest w Markdownie, a reszta bezczelnie w HTML-u. Blog generuje Pelican wyposażony w system wtyczek. Moim pierwszym pomysłem było dopisanie wtyczki, która wygeneruje odpowiednie pliki .txt podczas normalnego działania. Niestety, dokumentacja dotycząca wtyczek to głównie proces czytania kodu źródłowego zarówno projektu, jak i jakichś losowych gotowców operujących w hipotetycznym sąsiedztwie tego, co chcę osiągnąć.

Po kilku godzinach prób na ślepo postanowiłem, że wrócę do tego później i napiszę minimalistyczny generator „na teraz”. Jedna z tych prowizorek, co ma potencjał przetrwać nas wszystkich.

Jest trzy tygodnie później, wyszło słońce, porzuciłem komputery na rzecz wygodnych butów i plecaka. Już wróciłem, ale zaraz wychodzę znów, spróbuję więc skończyć ten tekst teraz.

Jak postanowiłem, tak zrobiłem. Zgodnie z tradycją pierwsze 90% projektu zrealizowałem w godzinę — czytanie plików tekstowych z dysku i zapisywanie ich nie jest specjalnie trudne. Następne 10% pracy zajęło jakieś 400% czasu. Problemy były wielorakie.

Treści fatalnej jakości

Nie mówimy tu o wartości literackiej, lecz o starych tekstach przeniesionych z Wordpressa. To prawdziwy gar zupy z tagów, bulgoczący i pachnący niezbyt zachęcająco. Jakimś pomysłem było zadeklarowanie listy legalnych tagów, które będę mógł zinterpretować. Ostatecznie uznałem, że te teksty są tak słabe, że ich nieczytelność jest praktycznie przysługą. Problem, mhm, rozwiązany.

Przypisy

Przypisy w blogu generowane są przez wtyczkę, która używa własnego tagu REL w nawiasach kwadratowych jako znacznika przypisu. Bez specjalnej miłości w sercu udałem się do testera wyrażeń regularnych i próbowałem napisać coś, co wychwyci potrzebny fragment. Musicie wiedzieć, że jedyne wyrażenie używane przeze mnie regularnie, to „kurwa”, proces ten zajął mi zatem więcej czasu niż powinien. Po testach postanowiłem, że wstawię przypisy pod paragrafami je zawierającymi, a nie na końcu tekstu. Wyglądało bardzo profesjonalnie, jakbym był blogerem z sponsorowanymi wpisami.

Linki

Ten sam problem co z przypisami, pomnożony przez to, że w moim lenistwie często używam zarówno markera z Markdownu, jak i <a>. Musiałem użyć nie tylko wyrażenia regularnego — bezwstydnie skopiowanego z internetu po godzinie walki — ale także BeautifulSoup celem wyłowienia tagów HTML-a. Zadziałało.

Obrazki

Chciałem zamienić obrazki na kolorowe „piksele” terminala. Używając notacji RGB, mogę bez problemu wykorzystać Pillow do przekonwertowania obrazu na tryb indeksowanej palety i przeskalować go do szerokości 76 znaków — docelowej szerokości tekstu, który chcę generować.

Poszło szybko, ale… efekt pozostawia dużo do życzenia. Poza „heh, fajne”, użyteczność obrazów przeskalowanych do 72px szerokości wydaje się być znikoma. Prawdopodobnie zmienię generator tak, żeby zamiast obrazków wstawiał odnośniki do nich, aby czytelnik mógł kliknąć samodzielnie.

Aktualizacja: obrazki działały okropnie, wszystko zależało od definicji terminala czytającego, więc po namyśle wywaliłem całość.

Markdown, «ANSI»

Nie miałem już zapału w sercu, by siadać do pisania parsera, który wypluwałby odpowiednio „wyeskejpowane” kody dla terminala w miejsce pogrubień, nagłówków i całego tego bajzlu. Znalazłem bibliotekę wyposażoną w komplet narzędzi i kiedy już oswoiłem się z jej konceptami, zagnałem ją do pracy.


Po prawie dwóch miesiącach mogę wreszcie zadeklarować, niczym lider wolnego świata — “MISSION ACCOMPLISHED” — prawie wszystko się udało™. A rzeczy, które się nie udały, najwyraźniej były kiepskimi pomysłami i zostały porzucone nie z powodu braku cierpliwości, tylko w wyniku głębokiej, filozoficznej retrospekcji.

Poprawiała Kaja ❤️

PS. curl -s https://fuse.pl/beton/curl-blog.html | less, duh. ;-)