Loading...

Blog

Firefox 130 experimele feature

08-09-2024
Nieuwe Firefox Labs feature doet stof opwaaien.

Readability implementatie in RSS reader

05-09-2024

Voor het lezen en tonen van RSS feeds, dacht ik dat het praktisch zou zijn om de inhoud van de link van de feed te tonen in een zogenaamde "readermode", zoals deze in veel browsers is ingebouwd. Na een kleine zoektocht lijkt het erop dat de reader mode van Safari gebaseerd is op de implementatie van Mozilla. En zo blijkt dat deze open-source is en op GitHub te vinden is: readability.

Dit klinkt natuurlijk als een interessante optie om te testen, maar ik gebruik .Net, en geen Node.js. Na wat zoekwerk kwam ik al snel meerdere implementaties tegen op nuget, waaronder SmartReader:

This library supports the .NET Standard 2.0. The core algorithm is a port of the Mozilla Readability library. The original library is stable and used in production inside Firefox. This way we can piggyback on the hard and well-tested work of Mozilla.

SmartReader also added some improvements on the original library, getting more and better metadata:

  • site name
  • an author and publication date
  • the language
  • the excerpt of the article
  • the featured image
  • a list of images found (it can optionally also download them and store as data URI)
  • an estimate of the time needed to read the article

Some of these fields are now present in the original library.

It also allows to perform custom operations before and after extracting the article.

Het inzetten van SmartReader is nogal simpel. Voeg de package toe aan je project en laat SmartReader de pagina ophalen en beoordelen:

var article = SmartReader.Reader.ParseArticle("https://arstechnica.com/information-technology/2017/02/humans-must-become-cyborgs-to-survive-says-elon-musk/");

if(article.IsReadable)
{
    Console.WriteLine($"Article title {article.Title}");
}

Er zijn nog diverse opties in te stellen, maar die sla ik voorlopig over. Voor het gebruik in mijn RSS reader, wil ik liever geen HTML hebben, maar Markdown tekst. Ik gebruik al langer de ReverseMarkdown packages, wat tot prima resultaten leid. Hier loop ik helaas wel tegen een probleem aan. Het blijkt dat de HTML soms veel tabs (of spaties) bevat, tussen een tekst node en een andere HTML node. Bijvoorbeeld een tekst gevolgd door een link. Maar ook een linefeed samen met tabs na een paragraph openings tag <p>. Hierbij worden de tabs niet verwijderd wat resulteert dat de markdown naar HTML deze tekst als <pre> formatteert.

Hierom is het verstandig om de HTML toch eerst nog wat op te schonen. AngleSharp is hier een prima oplossing voor. Ik heb ervoor gekozen om alle HTML element langs te lopen en de tekst in de textnode's op te ruimen:

public static void HtmlTextNodeTrim(INode node)
{
    if (node is IElement elementNode)
    {
        foreach (var childNode in elementNode.ChildNodes)
        {
            HtmlTextNodeTrim(childNode);
        }
    }
    else if (node is IText textNode)
    {
        var updatedText = 
            textNode.NodeValue = (textNode.Text ?? string.Empty).Trim() + " ";
    }
}

Tijdens het schrijven van dit artikel bedenk ik me wel dat dit problemen kan opleveren met een <pre> of <code> tag. Dit is voor latere zorg. Door dit te combineren met het herformatteren van de HTML zonder indenting, komt er HTML uit die prima door ReverseMarkdown kan worden omgezet:

using System.IO;
using AngleSharp;
using AngleSharp.Dom;
using AngleSharp.Html.Dom;
using AngleSharp.Html.Parser;

protected virtual string GetReadable(string url)
{
    try
    {
        var uri = new Uri(url);
        
        var article = Reader.ParseArticle(uri.ToString());
        if (!article.IsReadable)
            return null;
        
        // Get and sanitize HTML
        var html = HtmlSanitizeHelper.SanitizeHtml(article.Content);

        // Parse to markdown
        return ReadabilityHelper.HtmlToMarkdown(html);
    }
    catch (Exception ex)
    {
        // ... do some logging  
    }

    return null;
}

public class HtmlSanitizeHelper
{
    public static string SanitizeHtml(string html)
    {
        var parser = new HtmlParser();
        var document = parser.ParseDocument(html);

        HtmlTextNodeTrim(document.Body);
        
        return DocumentToHtml(document);
    }
    
    public static void HtmlTextNodeTrim(INode node)
    {
        if (node is IElement elementNode)
        {
            foreach (var childNode in elementNode.ChildNodes)
            {
                HtmlTextNodeTrim(childNode);
            }
        }
        else if (node is IText textNode)
        {
            var updatedText = 
                textNode.NodeValue = (textNode.Text ?? string.Empty).Trim() + " ";
        }
    }
    
    public static string DocumentToHtml(IHtmlDocument document)
    {
        using (var writer = new StringWriter())
        {
            document.ToHtml(writer);
            return writer.ToString();
        }
    }

    public static string HtmlToMarkdown(string html)
    {
        return new Converter(new Config()
        {
            UnknownTags = Config.UnknownTagsOption.Bypass,
            GithubFlavored = true,
            RemoveComments = true,
            SmartHrefHandling = true,
            TableWithoutHeaderRowHandling = Config.TableWithoutHeaderRowHandlingOption.Default
        }).Convert(html);
    }
}

MySql 8.4 in Docker

05-06-2024

Nog niet heel lang geleden is versie 8.4 van MySql uitgekomen. Hierin is een wijziging doorgevoerd m.b.t. de authenticatie. Voorheen kon met --default-authentication-plugin=mysql_native_password terug gevallen worden op de oudere (en vervallen) manier van de opslag van het wachtwoord. Na een update naar 8.4 start de server hierna niet meer op. Gelukkig hebben de ontwikkelaars hier een nog wel een optie voor toegevoegd.

Als vervanger kan nu --mysql-native-password=ON gebruik worden. Na aanpassen van de aanroep, werkt alles weer zoals vanouds:

services:
  db8:
    image: "mysql:8"
    command: --mysql-native-password=ON --max_connections=999 --max-allowed-packet=96M --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --skip-log-bin
    restart: always
    cap_add:
     - sys_nice
    volumes:
     - ${DOCKER_DATAPATH}/mysql8:/var/lib/mysql

Remote Desktop macOS

30-12-2023
macOS remote desktop is niet zo flexibel als RDP van Windows, maar een aantal (nieuwe) opties zijn zeker werkbaar

Lokale LLM's draaien met het gemak van containers

28-11-2023
Ollama biedt functionaliteit zoals Docker, maar dan voor Large Language Model.

.Net 8.0 en andere sdk's op macOS via brew

20-11-2023
Mogelijkheid om toch meerdere .Net SDK's met gebruik van Brew als package manager.

NuGet package versies via Directory.Packages.props

29-09-2023
Versimpelt nuget versie beheer via ManagePackageVersionsCentrally en Directory.Packages.props

Disk quota volume voor Docker

16-09-2023
Docker heeft momenteel out of the box geen mogelijkheid om een quota in te stellen op een volume. Dit kan via een tmpfs, maar deze is niet persistent bij herstart. Dit is op te lossen met een disk image.

Interessante en gratis AI tools

30-01-2023
Korte lijst van interessante en soms gratis AI tools

Bash template

09-01-2023
De originele template die ik ooit ergens gevonden heb om mijn bash scripts van een aantal standaard variabelen te voorziet, bleek niet om te kunnen gaan met spaties in de directory namen. De oplossing was eenvoudig toe te passen.

iPhone 2Fa zonder app

15-02-2022
Tot mijn verbazing is het mogelijk om 2Fa te gebruiken zonder extra app met macOS, IOS en IpadOS.

.NET Everywhere - Windows, Linux, and Beyond - Het einde van System.Drawing is in zicht

14-11-2021
Met de komst van .Net 6 zijn de eerste stappen genomen om System.Drawing uit te faseren. Zo is deze libary nu als "Windows Only" gemarkeerd. Gelukkig zijn er alternatieven om bestaande code simpel aan te passen en toekomst zeker te maken.

Reset mysql root password in docker container

09-11-2021
In veel gevallen start ik MySql in Docker zo op, dat er een random root wachtwoord wordt aangemaakt. Dit is prima, mits je of het wachtwoord uit de logfile haalt. In het geval dat je deze niet hebt, kan je mogelijk in de problemen komen.

.Net XUnit test herkend geen actions

23-10-2021
Asp.Net Core XUnit unittest project herkend geen actions

ZFS dataset niet aanwezig na stroomonderbreking

20-09-2021
Nadat de spanning van een bepaalde machine per ongeluk uitgevallen was, starte een aantal Docker services op deze machine niet meer op. Het blijkt al snel dat Docker niet gestart is, oftewel niet heeft kunnen opstarten.

Zfs snapshot als standaard gebruiker

11-08-2021
Voeg rechten toe aan een gewone gebruiker om snapshots te maken

Net 5.0 service op MacOS

19-06-2021
Uitvoeren van een achtergrond service via Launchd op MacOS, gemaakt in DotNet Core

Opstarten nginx met ontbrekende (Docker) host

22-02-2020
Herstarten nginx zonder foutmelding als reverse proxy host ontbreekt

DotNet Core achtergrond service onder Linux

28-12-2019
Systemd service onder linux met dotnet core

Uitbreiden swap

15-12-2019
Meer virtueel geheugen toewijzen aan linux server

Verplaatsen van docker storage lokatie

05-09-2019
Verplaats docker data storage naar andere partitie

Testen verplaatsen Docker volume van Mailcow naar ZFS pool

06-05-2019
Na de installatie van Mailcow via Docker op een Linux productie server, blijkt dat de opslag van de mail data in een Docker volume staat, waardoor de root partitie van de server langzaam volloopt. Mailcow biedt een beschrijving om dit aan te passen.