# Resurrecting My Old Blog with Archive.org and a Loot of C#

<!--category-- Imported, .NET, Archive.org -->
<datetime class="hidden">2025-11-24T12:00</datetime>

Οπότε μπορεί να πρόσεξες εκατοντάδες. ["new" blog posts](https://www.mostlylucid.net/blog/category/Imported) εμφανίζονται πρόσφατα. Λοιπόν, δεν είναι καθόλου νέα - είναι παλιά. Όπως, 2004 παλιά. Επιτέλους έφτιαξα ένα εργαλείο για να σώσει το περιεχόμενό μου από το ψηφιακό νεκροταφείο που ήταν το παλιό μου blog στο κυρίως διαυγή.co.uk.

## Γιατί Archive.org είναι απολύτως λαμπρό

Πριν βουτήξω στα τεχνικά, πρέπει να φωνάξω [Αρχείο Διαδικτύου](https://archive.org/) Αυτή η μη κερδοσκοπική οργάνωση αρχειοθετεί αθόρυβα το διαδίκτυο από το 1996, διατηρώντας δισεκατομμύρια ιστοσελίδες που διαφορετικά θα χαθούν για πάντα.

Σκεφτείτε το για ένα δευτερόλεπτο. Κάθε δημοσίευση blog που γράψατε το 2005, κάθε σελίδα GeoCities, κάθε προφίλ MySpace - υπάρχει μια αξιοπρεπής πιθανότητα να είναι ακόμα προσβάσιμη μέσω του Archive.org. Διοικούν ουσιαστικά ένα μουσείο ολόκληρου του διαδικτύου, χρηματοδοτούμενο από δωρεές και επιχορηγήσεις.

Όταν ο παλιός μου πάροχος hosting εξαφανίστηκε (μαζί με τα backups μου επειδή ήμουν SMART έτσι), νόμιζα ότι όλο αυτό το περιεχόμενο είχε φύγει για πάντα. Αποδεικνύεται ότι η Wayback Machine είχε προσεκτικά στιγμιότυπα site μου για χρόνια. Archive.org αρκετά κυριολεκτικά έσωσε 6+ χρόνια της ιστορίας blogging μου.

Αν δεν τους έχεις δωρίσει ποτέ, σκέψου να το κάνεις.

## Το πρόβλημα: Το blog μου ήταν ένα χάος

Εδώ είναι το θέμα σχετικά με τη λειτουργία ενός blog από το 2004 έως το 2010 - web τεχνολογίες άλλαξαν πολλά κατά τη διάρκεια εκείνης της περιόδου. Και προφανώς, άλλαξα τη ρύθμιση blogging μου τουλάχιστον τρεις φορές:

1. **Πρώιμες Ημέρες (2004)**: Some homebrew ASP.NET thing with content packed in `<div class="post">` μέσα σε ένα `<form>` στοιχείο (επειδή όλα ήταν μια μορφή τότε)
2. **Μεσαία περίοδος**: Διαφορετική δομή προτύπου, ημερομηνίες σε διαφορετικούς τόπους
3. **Αργότερα Χρόνια**: Άλλη μια αναδιάρθρωση με ελαφρώς διαφορετικούς επιλογέαυς

Από μνήμης χρησιμοποιούσε κάτι έθιμο τότε. [SubText](http://beletsky.net/2010/09/subtext-open-source-blogging-engine.html) (Phil Hack's blogging thing). Followed by Community Server (a [Telligent](https://community.telligent.com/) thing ASP.NET χρησιμοποιείται για να φιλοξενήσει ιστοσελίδες, από μια άλλη πρώην ASP, NET PM Rob Howard) . Όλα αυτά είχαν διαφορετικούς τρόπους ενημέρωσης και διαφορετικούς τρόπους εμφάνισης περιεχομένου.

Αυτό σήμαινε ότι κάθε εργαλείο εξαγωγής χρειάζεται να είναι αρκετά ευέλικτο για να χειριστεί πολλαπλές δομές HTML. Ένα "ένα μέγεθος ταιριάζει όλα" δεν επρόκειτο να το κόψει.

## Εισάγετε το ArchiveOrg Importer

Το έφτιαξα. [ArchiveOrg Importer](https://github.com/scottgal/mostlylucid.nugetpackages/tree/main/Mostlylucid.ArchiveOrg) Είναι μια εφαρμογή .NET 9.0 κονσόλας που:

1. **Σεβάζεται τα όρια χρήσης του Archive.org** - Είναι ένα μη κερδοσκοπικό τρέξιμο για δωρεές, έτσι σφυροκοπώντας τους διακομιστές τους θα ήταν ένα τρομερό πράγμα να κάνεις
2. **Λήψεις αρχειοθετημένων σελίδων μεταξύ παραμετροποιήσιμων ημερομηνιών**
3. **Εκχύλισμα περιεχομένου blog από πολλαπλές δομές HTML**
4. **Δημιουργεί καθαρό Markdown** στην τρέχουσα μορφή blog μου
5. **Χρησιμοποιεί Ollama για να δημιουργήσει χρήσιμες ετικέτες** - γιατί δεν του ρίχνεις λίγη μαγεία LLM;

### Πώς Λειτουργεί

Το εργαλείο ακολουθεί μια αρχιτεκτονική αγωγών με τρεις κύριες φάσεις:

```
Archive.org CDX API → Download HTML → Convert to Markdown → Generate Tags → Output Files
```

#### Φάση 1: Ανακρίνοντας το Αρχείο

Το εργαλείο χρησιμοποιεί Archive.org's [CDX API](https://github.com/internetarchive/wayback/tree/master/wayback-cdx-server) για να βρείτε όλα τα αρχειοθετημένα στιγμιότυπα του blog μου. Αυτό το API επιστρέφει μια λίστα των συλληφθέντων URL με χρονοσφραγίσεις, τύπους MIME και κωδικούς κατάστασης HTTP.

```csharp
// The CDX query builds a URL like this:
// https://web.archive.org/cdx/search/cdx?url=mostlylucid.co.uk/posts/&output=json&collapse=urlkey
```

Η `collapse=urlkey` παράμετρος είναι έξυπνο - επιστρέφει μόνο το τελευταίο στιγμιότυπο για κάθε μοναδικό URL, το οποίο μειώνει δραματικά τον αριθμό των αντιγράφων που πρέπει να ασχοληθεί με.

Χρησιμοποιώ επίσης μοτίβα regex για να φιλτράρω URL. `/posts/[number].aspx`, έτσι:

```json
{
  "IncludePatterns": ["/posts/\\d+\\.aspx$"]
}
```

Με αυτόν τον τρόπο παίρνω μόνο πραγματικές αναρτήσεις blog, όχι τις σελίδες αρχείων, τις σελίδες κατηγορίας, ή RSS feeds.

#### Φάση 2: Το να είσαι καλός πολίτης με ποσοστό περιορισμού

Archive.org είναι μια δημόσια υπηρεσία. Δεν έχουν τον προϋπολογισμό υποδομής της Google ή Amazon. Έτσι το downloader είναι σκόπιμα συντηρητικό:

```csharp
// Default: 5 seconds between requests, single-threaded downloads
"RateLimitMs": 5000,
"MaxConcurrentDownloads": 1
```

Ναι, αυτό σημαίνει λήψη εκατοντάδων θέσεων παίρνει λίγο χρόνο. Αλλά είναι το σωστό πράγμα να κάνουμε. Το εργαλείο χειρίζεται επίσης 429 (όριο) απαντήσεις χαριτωμένα με εκθετική backoff.

Το Archive.org προσθέτει scripts στη γραμμή εργαλείων και ξαναγράφει URLs στο αιχμαλωτισμένο HTML.

```csharp
private static string CleanWaybackArtifacts(string html)
{
    // Remove the interactive Wayback toolbar
    html = WaybackToolbarRegex().Replace(html, string.Empty);
    // Remove playback.archive.org script references
    html = WaybackScriptRegex().Replace(html, string.Empty);
    // Strip archival metadata comments
    html = WaybackCommentRegex().Replace(html, string.Empty);
    // Rewrite archived URLs back to original paths
    html = WaybackUrlRewriteRegex().Replace(html, "$1$2");
    return html;
}
```

Τα μοτίβα regex χειρίζονται:

- `<!-- BEGIN WAYBACK TOOLBAR INSERT -->...<!-- END WAYBACK TOOLBAR INSERT -->` - η γραμμή εργαλείων HTML
- `<script>` αναφορές ετικετών `playback.archive.org`
- Archive Metataltics comments
- Πρόθεμα URL όπως `https://web.archive.org/web/20040527/` που προετοιμάζονται σε όλους τους συνδέσμους

#### Φάση 3: Ο Εφιάλτης Εξαγωγής Περιεχομένου

Θυμάσαι που ανέφερα ότι το blog μου άλλαξε δομή τρεις φορές;

Η πρωτογενής εξαγωγή χρησιμοποιεί έναν επιλογέα CSS:

```json
{
  "ContentSelector": "div.post"
}
```

Αλλά εδώ είναι μια διασκεδαστική ιδιοτροπία - σε κάποιες εκδόσεις του παλιού μου site, το `div.post` ήταν μέσα σε ένα `<form>` στοιχείο. Ο κώδικας πρέπει να εξάγει το περιεχόμενο ΠΡΙΝ την αφαίρεση ανεπιθύμητων στοιχείων, διαφορετικά την αφαίρεση `<form>` tags wouldnuke the actual blog content:

```csharp
// In ConvertFileAsync - the order here is critical
var contentNode = ExtractMainContent(doc);
if (contentNode == null)
{
    _logger.LogWarning("Could not find main content in {File}", htmlFilePath);
    return articles;
}

// NOW we can safely remove unwanted elements from within the extracted content
RemoveUnwantedElementsFromNode(contentNode);
```

Η `ExtractMainContent` μέθοδος χρησιμοποιεί μια ιεραρχική αναζήτηση για να βρει το περιεχόμενο:

```csharp
// For selectors like "div.post", split and search by element + class
node = doc.DocumentNode.Descendants()
    .FirstOrDefault(n =>
        n.Name.Equals(elementName, StringComparison.OrdinalIgnoreCase) &&
        HasExactClass(n, className));
```

Το εργαλείο έχει επίσης οπίσθιους επιλογέαυς εάν ο αρχικός αποτυγχάνει:

1. `div.blogpost`, `div.singlepost`, `article`
2. `#content`, `#main-content`, `#PostBody`
3. `.post-content`, `.entry-content`, `.article-content`
4. Επιτέλους, μόνο το `<body>` αν όλα τα άλλα αποτύχουν

Στη συνέχεια, υπάρχει μια μακρά λίστα των στοιχείων για να απογυμνώσει μετά την εξαγωγή περιεχομένου:

```json
{
  "RemoveSelectors": [
    "nav", "header", "footer", ".sidebar", ".advertisement",
    ".comments", ".social-share", ".related-posts", "script",
    "style", "noscript", "iframe", "#commentform", ".postNav"
  ]
}
```

#### Φάση 4: Παραγωγή Markdown

Μόλις έχουμε καθαρό περιεχόμενο HTML, [ΑντιστρόφωςMarkdown](https://github.com/mysticmind/reversemarkdown-net) χειρίζεται τη βαριά ανύψωση της μετατροπής σε GitHub-γεύση Markdown.

Το παλιό HTML συχνά είχε περίεργη εσοχή που θα μπέρδευε τους παριστάμενους Markdown (εντοπισμένες γραμμές γίνονται μπλοκ κώδικα!).

```csharp
// Removes leading whitespace from non-code lines
// Preserves code block formatting (respects ``` fences)
// Removes excessive blank lines (max 2 consecutive)
```

Η τελική παραγωγή περιλαμβάνει τη μορφή πρώτης ύλης του blog μου:

```markdown
# Article Title

<datetime class="hidden">2004-05-27T23:21</datetime>
<!--category-- mostlylucidcouk, Imported, SomeCategory -->

Article content here...
```

#### Φάση 5: LLM-Powered Tag Generation

Τώρα για το διασκεδαστικό μέρος. Παλαιές δημοσιεύσεις blog συχνά δεν είχαν ετικέτες σε όλα, ή ετικέτες που δεν είχαν νόημα για την τρέχουσα δομή του site μου. Έτσι, ενσωμάτωσα Ollama για να αναλύσει το περιεχόμενο και να δημιουργήσει σχετικές ετικέτες.

Η διαμόρφωση είναι απλή:

```json
{
  "Ollama": {
    "BaseUrl": "http://localhost:11434",
    "Model": "gemma3:4b",
    "Temperature": 0.3,
    "MaxTags": 5,
    "Enabled": true
  }
}
```

Χρησιμοποιώ `gemma3:4b` καθώς είναι γρήγορο και αρκετά μικρό για να τρέξει σε τοπικό επίπεδο χωρίς μεγάλη φασαρία. Η χαμηλή θερμοκρασία (0.3) διατηρεί την έξοδο συνεπής δεν θέλουμε δημιουργικές παραισθήσεις στις ετικέτες μας. Σημείωση; για το blog μου αυτό λειτούργησε ως οι δημοσιεύσεις ήταν σύντομες, αν το δικό σας είναι πλέον σίγουρο ότι θα εξετάσουμε τις τεχνικές chunking και summarisation fo ταιριάζει στο παράθυρο πλαίσιο του μοντέλου σας.

##### Χειρισμός μακροχρόνιων ταχυδρομείων

Εδώ είναι ένας πρακτικός περιορισμός: LLMs έχουν παράθυρα πλαίσιο, και αντλεί ένα ολόκληρο blog post σε αυτά για την παραγωγή ετικετών είναι σπάταλη. Το εργαλείο truncates περιεχόμενο σε 3000 χαρακτήρες:

```csharp
var truncatedContent = content.Length > 3000
    ? content[..3000] + "..."
    : content;
```

Για την παραγωγή ετικετών, οι πρώτοι 3000 χαρακτήρες συνήθως περιέχουν αρκετό πλαίσιο για να κατανοήσουν τι είναι η θέση.

```
Generate up to 5 tags, short (1-3 words), focusing on:
.NET, C#, ASP.NET, JavaScript, Docker, Database, API, Security, DevOps, Cloud
```

Η απάντηση είναι αμυντικός. Αν ο Όλαμα επιστρέψει σκουπίδια ή φορές έξω, απλά παίρνουμε μια άδεια λίστα ετικετών αντί να συντρίβουμε ολόκληρο τον αγωγό.

### Ημερομηνία Εξαγωγής: Μια Πολυ-Στρατηγική Προσέγγιση

Το παλιό μου blog αποθηκεύτηκε ημερομηνίες σε διάφορα μέρη κατά τη διάρκεια των ετών. Το εργαλείο προσπαθεί πολλαπλές στρατηγικές:

1. **Ρυθμιζόμενος επιλογέας** (π.χ., `.postfoot`)
2. **Meta tags**: `article:published_time`, `DC.date.issued`
3. **HTML5 `<time>` στοιχεία**
4. **Κατηγορίες κοινών ημερομηνιών**: `.date`, `.post-date`, `.entry-date`
5. **Μοτίβα Regex** σε ακατέργαστη HTML (μορφή ISO, χωρισμένος κ.λπ.)
6. **ΦόλλμπακCity name (optional, probably does not need a translation)**: Το αρχείο στιγμιότυπο ημερομηνία το ίδιο

Μια ιδιαίτερα ενοχλητική μορφή ήταν το παλιό μου blog template's "posted on Thursday, May 27, 2004 11:21 PM" string.

### Η ενορχήστρωση αγωγών

Το πιο δροσερό αρχιτεκτονικό κομμάτι είναι πώς κατεβάσετε και να μετατρέψετε τρέχει παράλληλα χρησιμοποιώντας .NET κανάλια:

```csharp
var channel = Channel.CreateBounded<string>(10);

// Producer: downloads and writes file paths to channel
// Consumer: reads file paths and converts to markdown
```

Αυτό σημαίνει μετατροπή αρχίζει μόλις το πρώτο αρχείο κατεβάσει, αντί να περιμένει για όλες τις downloads να ολοκληρωθεί. Η οριοθετημένη χωρητικότητα (10 στοιχεία) παρέχει backpressure - εάν η μετατροπή πέσει πίσω, κατεβάζοντας επιβραδύνει προς τα κάτω για να ταιριάζει.

## Περιορισμοί και Γκότας

Ας είμαστε ειλικρινείς σχετικά με το τι αυτό το εργαλείο δεν μπορεί να κάνει:

1. **Είναι πολύ συγκεκριμένο στο blog μου** Οι επιλογέαι, τα μοτίβα και η ημερομηνία εξαγωγής είναι όλα συντονισμένα για τις περισσότερες διαυγής.co.uk. Θα πρέπει να προσαρμόσετε τα πάντα για μια διαφορετική τοποθεσία.

2. **Το Archive.org δεν έχει τα πάντα.** Μερικές σελίδες δεν αρχειοθετήθηκαν, ή αρχειοθετήθηκαν με σπασμένα CSS/εικόνες.

3. **Οι εικόνες είναι καλύτερης ποιότητας** - Το εργαλείο προσπαθεί να κατεβάσει εικόνες από την Wayback Machine, αλλά πολλά έχουν απλά φύγει για πάντα.

4. **Νεκροί σύνδεσμοι παντού.** - Εξωτερικοί σύνδεσμοι από το 2004 δείχνουν σε ιστοσελίδες που δεν υπάρχουν πλέον. Δουλεύω πάνω σε μια ξεχωριστή λύση για αυτό (αυτόματο Archive.org link replacement in a mediumware - blog post coming soon!).

5. **Οι ετικέτες LLM είναι ατελείς** Οι ετικέτες Ollama είναι συνήθως λογικές, αλλά περιστασιακά χάνουν το σημάδι.

6. **CDX API truncation** Για ιστοσελίδες με χιλιάδες σελίδες, το CDX API μπορεί να επιστρέψει trunnated αποτελέσματα. Ο κώδικας χειρίζεται αυτό με χάρη, αλλά μπορεί να χάσετε μερικές σελίδες.

## Το τρέξιμο

Αν θέλετε να προσαρμόσετε αυτό για το δικό σας site (θα χρειαστεί προσαρμογή), οι εντολές είναι:

```bash
# Full pipeline (download + convert)
dotnet run -- full

# Just download HTML from Archive.org
dotnet run -- download

# Just convert existing HTML files to Markdown
dotnet run -- convert
```

Το εργαλείο υποστηρίζει χαριτωμένο κλείσιμο (Ctrl+C) και μπορεί να συνεχίσει από εκεί που άφησε μακριά, δεδομένου ότι τα αρχεία είναι cached τοπικά.

## Τα Αποτελέσματα

Μετά το τρέξιμο αυτό στο παλιό μου blog, ανακάλυψα αναρτήσεις που χρονολογούνται πίσω στο [1 Ιανουαρίου 2004](/blog/365) και πριν! Διάβασμα μέσα από αυτά είναι ένα συναρπαστικό ταξίδι στο χρόνο. Web αναπτυξιακές συζητήσεις από πριν jQuery υπήρχε. Δημοσιεύσεις για τεχνολογίες που τώρα είναι εντελώς παρωχημένες. Και μερικές δυσάρεστες απόψεις που είχα ως νεότερος προγραμματιστής.

Μπορείτε να βρείτε όλες τις εισαγόμενες θέσεις χρησιμοποιώντας το [Εισαγωγή](/blog/category/Imported) Ετικέτα κατηγορίας.

## Ποιο είναι το επόμενο;

Το εισαγόμενο περιεχόμενο έχει ένα LOT νεκρούς συνδέσμους που είναι μόνο η φύση του 20-year-old web περιεχόμενο. I [Κατασκεύασε μια λύση μεσαίου λογισμικού](/blog/the-war-on-404) ότι:

1. Ανιχνεύστε 404 για παλιά URLs
2. Αυτόματη εύρεση του πλησιέστερου στιγμιότυπου Archive.org
3. Επαναφορά ή εμφάνιση της αρχειοθετημένης έκδοσης

## Αναδίπλωση

Χτίζοντας αυτό το εργαλείο ήταν ένα έργο Σαββατοκύριακο που μετατράπηκε σε κάτι πραγματικά χρήσιμο. Αν έχετε χάσει περιεχόμενο από ένα παλιό blog, υπάρχει μια αξιοπρεπής πιθανότητα Archive.org έχει. Και αν είστε άνετα με C#, οι τεχνικές εδώ (CDX API querying, HTML εξαγωγή περιεχομένου, γενιά Markdown, LLM tagging) θα μπορούσαν να προσαρμοστούν για το δικό σας έργο ανάκαμψης.

Ο κώδικας είναι σε [github.com/scottgal/κυρίως διαυγή.nuget packages](https://github.com/scottgal/mostlylucid.nugetpackages/tree/main/Mostlylucid.ArchiveOrg). Δεν είναι μια γυαλισμένη βιβλιοθήκη είναι ένα εργαλείο κατασκευής σκοπού για τη συγκεκριμένη κατάστασή μου - αλλά μπορεί να σας δώσει ιδέες για τις δικές σας αρχειακές περιπέτειες.

Και σοβαρά, πήγαινε δωρεά στο Archive.org. Κάνουν σημαντική δουλειά.