Štítek: nástroje

Čtyři dny blogu

Za poslední dny, i když se to nezdá, jsem na blogu udělal 116 commitů ve 24 pull requestech. Něco z toho je vidět přímo tady na webu, to podstatné se ale odehrálo pod kapotou. Ale nejdřív prostý výčet toho, co se povedlo:

Co je hotové

  • audio jako plnohodnotný typ postu, citace s atribucí a chat posty
  • tvrdá zalomení a task listy v markdownu
  • médium si post nárokuje jen tehdy, když je text opravdu popisek — 104 starých příspěvků se tím přesunulo do správného typu
  • menu ukazuje jen typy, které web skutečně má, takže AUDIO ani CHAT tu zatím neuvidíte; objeví se samy s prvním takovým postem
  • aktivní položka v menu je konečně barevně odlišená a první položka se jmenuje Vše, ne Domů
  • časová zóna se respektuje i při zobrazení, nejen při zápisu
  • naplánované publikování — draft s budoucím datem se pustí ven sám
  • vlastní favicon a ikona pro plochu na iOS
  • widget s posledními příspěvky z Bluesky a obecný widget na jakékoliv RSS

Pod kapotou — z nástroje pro jeden blog je projekt

Tohle je ta část, kvůli které se ty čtyři dny nedají shrnout do odrážky.

Nástroj, o kterém jsem tu celou dobu psal, přestal být nástrojem jen pro tenhle web. Vytáhl jsem engine do separátního repozitáře pod názvem blog.sh, dal mu licenci MIT a od 30. července je veřejný.

Skoro to i platilo. Skoro — protože to znamená, že v kódu nesmí zůstat nic mého. Barvy webu, které byly natvrdo v CSS, se přestěhovaly do konfigurace: sedm barev pro světlý a sedm pro tmavý režim, zbytek se z nich dopočítá.

Všechny texty se přeložily do skutečných locale souborů, takže engine mluví česky, anglicky a nově i německy — a to jak na webu, tak i v průvodci v terminálu. Konfigurace a grafika každé instalace žijí mimo git, aby si kdokoliv mohl aktualizovat kód, aniž by si přepsal vlastní banner.

Nejlepší test je druhá instalace, takže existuje: blogsh.app, web o tomto enginu, postavený tímto enginem. Dva weby na jednom kódu odhalí za týden víc než měsíc přemýšlení, co by se mohlo pokazit.

Změnil se i způsob, jakým se sem dostávají změny. Dřív jsem kód na server kopíroval rsyncem. Dnes je server obyčejný git klon a nová verze se nasazuje git pullem — sean.cz sleduje moji pracovní větev, blogsh.app jen to, co je vydané.

Z jednoho migračního skriptu se také mezitím stal celý importní podsystém. Umí sedm zdrojů — Bluesky, Mastodon, Pixelfed, Tumblr, Twitter/X, WordPress s RSS a od včerejška Instagram — a ke každému se dostanete jak průvodcem, tak skriptem, přičemž pod tím běží jediná implementace. Import taky přestal být operace, kterou spustíte omylem: potvrzuje se opsáním počtu příspěvků, ne stiskem y. Když jednou naliju do webu dva tisíce cizích postů, chci to mít na svědomí vědomě.

Podobně se otevřelo nasazování. Surfer, který tenhle web hostuje, byl původně jediná možnost; dnes jsou vedle něj místní adresář, rsync, git (a tím i GitHub Pages), rclone a SFTP. Pojistky proti tomu, aby rozbitý build smazal půlku webu, platí pro všechny stejně.

A protože komentáře pod články sem tahám z Mastodonu, dostala stejnou možnost i druhá síť: web může komentáře a oznamovací příspěvky vést přes Bluesky. Buď jedno, nebo druhé — sčítat reakce ze dvou sítí do jednoho vlákna nedává smysl.

Nakonec terminál. Průvodce, o kterém jsem psal minule jako o číslovaném menu, umí šipky, jednoklávesové odpovědi a vlastní QR kód — po založení draftu se rozsvítí na obrazovce a jeho vyfocením mám náhled rozepsaného textu v telefonu. Žádná knihovna, ten kodér je taky součást repozitáře.

Zbytek těch čtyř dnů spolykala dokumentace a testování na cizích strojích — instalace na Macu, na Linuxu a na Windows přes WSL. Cíl je jednoduchý: kdo si to chce nainstalovat, ať to zvládne bez ptaní.

Chyby, které to vytáhlo na světlo

  • nový příspěvek se stejným názvem ve stejném roce tiše přepsal ten starší
  • nedotčený draft se publikoval, jako by měl ručně zadané datum, a přišel tím o oznamovací příspěvek — tedy i o komentáře
  • odstavec zabalený do <div> se rozsekal na blok za každý kus a cestou přišel o tučné písmo
  • HTML entity, které nebyly v převodní tabulce, mizely i s písmenem uprostřed slova
  • příliš dlouhý nadpis vyrobil čtyřsetznakovou adresu příspěvku
  • náhled importu hlásil nula médií, tedy přesně to číslo, kvůli kterému náhled existuje
  • neodpovězený dotaz na zdroj importu vybral poslední položku místo toho, aby akci zrušil
  • drafty nešlo smazat z nabídky hned po uložení
  • politika obsahu tiše blokovala skript s překlady, takže se texty vykreslované v prohlížeči zobrazovaly prázdné a nic to nehlásilo

Co dál?

Soustředil jsem se teď na release verze 1.0, přípravu webu ./blog.sh, něco designu, a také už připravuji další funkcionality. Pár nápadů už mám. Hlavně ale zítra bude ten den, kdy to všechno vypustím do světa a jsem zvědavý, zda budou vůbec nějaké reakce a zda budou pozitivní, a nebo ne. Těším se, a zároveň mám i obavy. Uvidíme.

Číst dál

Draft, náhled, koš — jak dneska pracuju s příspěvkem

Když jsem tu naposledy psal o tom, jak je tenhle blog postavený, manage-post.sh uměl v podstatě tři věci: napsat, upravit a smazat. Fungovalo to, ale mělo to pár much, na které jsem přišel až za provozu — a protože je psaní kódu k tomuhle blogu skoro stejná zábava jako psaní příspěvků, sedl jsem si a předělal to. Tenhle post je o tom, jak s příspěvkem pracuju teď.

Draft, ne rovnou na web

add nikdy nepublikuje rovnou. Vždycky vznikne draft s vlastní skrytou adresou (/draft/<náhodný token>/...) — dá se otevřít z telefonu i uprostřed rozepsaného textu, ale nikdo jiný ji neuhodne, protože není nikde odkazovaná ani v žádném výpisu. Teprve když jsem s textem hotový, přijde na řadu skutečná otázka: publikovat, nechat rozepsané jako draft, nebo se vrátit zpátky do editoru.

Náhled na draft postu pro blog
Náhled na draft postu pro blog

Publish uměl jednu ošklivou věc

Tohle byla ta nejzávažnější chyba, na kterou jsem přišel: publish post publikoval okamžitě, jakmile jsem vybral slug ze seznamu. Žádný náhled, žádné "jsi si jistý" — jen holé rozhodnutí udělané za mě. Chtěl jsem se ale ještě podívat, jak draft vypadá, než ho pustím ven. Teď publish udělá přesně to, co add po založení — ukáže náhled a zeptá se, co dál. Skutečnou publikaci spouští až vědomá volba v tom menu, ne samotné zavolání příkazu.

Unpublish — zpátky do šuplíku

Přibyla i opačná operace: unpublish vrátí publikovaný příspěvek zpátky do draftu. Hodí se, když si po publikaci všimnu překlepu, který nechci opravovat narychlo, nebo když se rozhodnu text ještě pořádně přepracovat. Součástí je i smazání přidruženého tootu na Mastodonu přes jeho API — jinak by po dobu, než příspěvek zase publikuju, na síti visel odkaz na stránku, která dočasně neexistuje. Při další publikaci navíc dostane nové, aktuální datum — chová se to jako čerstvě napsaný text, ne jako by se jen tiše přemístil v archivu.

Koš místo nevratného smazání

delete dřív smazal JSON i všechna přidružená média natvrdo. Žádný git u obsahu, žádná záloha — jeden překlep ve slugu a je to pryč. Teď delete přesouvá všechno do trash/, a restore <slug> to vrátí přesně tam, kde to bylo. Není to plnohodnotná historie verzí, jen jedna úroveň zpět — ale přesně to mi chybělo.

Toot na požádání

Někdy zůstane příspěvek bez tootu zajišťujícího vaše reakce z Mastodonu — třeba u starých migrovaných věcí z Tumblru, nebo když se odeslání tootu při publikaci nepovede (výpadek sítě, expirovaný token). Dřív jsem s tím nemohl nic dělat jinak než ručně. Nový příkaz toot <slug> pošle komentářový toot dodatečně, ke komukoliv publikovanému, kdykoliv. Existující toot ale nikdy nepřepíše — když už jeden je, druhý se neposílá, protože pro to není důvod.

Průvodce pro dny, kdy zapomenu příkazy

Nástroj má dnes devět různých akcí a nechci si je pamatovat nazpaměť pokaždé, když sednu k psaní. Stačí teď spustit ./blog.sh bez ničeho a naskočí jednoduché číslované menu — vyberu si, co chci udělat, a po dokončení se vrátím zpátky do stejného menu, dokud neřeknu konec. Přesná stejná logika jako předtím u CLI, jen v přívětivější podobě pro dny, kdy nechci nic ťukat z hlavy.

Průvodce funkcemi blogu
Průvodce funkcemi blogu

Přejmenování a co bude dál

Nakonec i drobnost: manage-post.sh jsem přejmenoval na blog.sh — název, který sedí líp k tomu, co ten nástroj dneska umí, a protože nezůstal svázaný jen s prací nad jedním příspěvkem. Zbytek pojmenování v repozitáři (deploy-web.sh, refresh-sidebar.sh) jsem záměrně nechal být — dělají jinou, úzce vymezenou práci a přejmenování by tomu nic nepřidalo.

Číst dál

Shooter: generátor promo screenshotů, co se osamostatnil

Když jsem pro TangerineUI Classic přidával nové barevné varianty, potřeboval jsem k nim pokaždé to samé: promo screenshot do README – browser okno v light i dark módu diagonálně vedle sebe, k tomu iPhone mockup, na barevně tónovaném pozadí. Ručně to skládat mě po 5 minutách přestalo bavit a tak vznikl malý Python skript schovaný hluboko v art/Screenshots/ repa.

Screenshot Deník N vytvořený Shooterem
Screenshot Deník N vytvořený Shooterem

Vykostění

Skript uměl jen jednu věc pro jeden konkrétní projekt – natvrdo zadrátované jméno souborů TangerineUI-<variant>.png, natvrdo osm barevných variant. Když jsem ale potřeboval podobné promo obrázky i pro Fedík, Katalog nebo Sloníka, vyplatilo se ho z TangerineUI vytrhnout a zobecnit. Tak vznikl Shooter – samostatný nástroj, co spustíš jako:

python3 shoot.py <jméno> --bg <barva>

a on si sám v screenshots/ najde <jméno>-light.png, -dark.png a volitelně i -iphone.png.

Jak to funguje

Trik je v tom, že se nefotí žádný skutečný telefon ani prohlížeč. Je tam jednou provždy připravená šablona – ořezané browser chrome s drop shadow a čistý iPhone rámeček s "vypáleným" stavovým řádkem a transparentní dírou uprostřed. Screenshoty se pořizují v Chrome DevTools na přesný viewport a DPR, a skript je pak jen nalepí do šablony přes Pillow.

Detektivka se stínem

Nejzábavnější část bylo lovení jednoho vizuálního bugu – v levém horním rohu okna se objevovala falešná, moc tmavá skvrna stínu, kterou jsem předtím vždycky opravoval ručně kopírováním čistého kousku pozadí přes to špatné místo. Ukázalo se, že šablona má v sobě zapečený druhý, přebytečný stín navázaný přesně na výšku toolbaru – takže se tam sčítaly dva stíny najednou. Řešení nakonec bylo přesně to, co jsem dělal ručně, jen automatizované: najít přesnou hranici (na pixel) a přelepit ji čistým pruhem pozadí zespodu.

Co z toho je

Shooter teď umí udělat promo screenshot pro libovolný web – fedik.online, katalog.zpravobot.news i Sloníka jsem jím prohnal bez jediné úpravy kódu, jen se změnou jména a barvy.

Číst dál