2026-09-20 08:31:23 +02:00
|
|
|
using System.IO.Compression;
|
|
|
|
|
using System.Text.Json;
|
|
|
|
|
using System.Text.Json.Serialization;
|
|
|
|
|
|
|
|
|
|
namespace wp2ghost
|
|
|
|
|
{
|
|
|
|
|
// =============================================================================
|
|
|
|
|
// GhostExporter — Ghost ZIP erstellen
|
|
|
|
|
// =============================================================================
|
|
|
|
|
static class GhostExporter
|
|
|
|
|
{
|
|
|
|
|
private static string BaseDir = "";
|
|
|
|
|
private static string MarkdownDir = "";
|
|
|
|
|
|
|
|
|
|
public static int PostCount => PostFetcher.PostCount;
|
|
|
|
|
|
|
|
|
|
public static void Init(string baseDir)
|
|
|
|
|
{
|
|
|
|
|
BaseDir = baseDir;
|
|
|
|
|
MarkdownDir = Path.Combine(baseDir, "markdown");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static async Task CreateZipAsync()
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine();
|
|
|
|
|
Console.WriteLine("Erstelle Ghost ZIP-Datei...");
|
|
|
|
|
|
|
|
|
|
var posts = PostFetcher.Posts;
|
|
|
|
|
if (posts.Count == 0)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine("Keine Beiträge geladen. Bitte zuerst Option 1 ausführen.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2026-10-14 19:12:29 +02:00
|
|
|
string outputPath = Path.Combine(BaseDir, Importer.OutputZipPath);
|
2026-09-20 08:31:23 +02:00
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
//PostFetcher.SaveAllMarkdownFiles();
|
|
|
|
|
|
2026-10-14 19:12:29 +02:00
|
|
|
// Links zwischen den eigenen Beiträgen auf Ghost umschreiben (Kopie, Original bleibt unverändert)
|
|
|
|
|
int internalLinks = 0;
|
|
|
|
|
var exportPosts = posts.Select(p =>
|
|
|
|
|
{
|
|
|
|
|
var rewritten = InternalLinkManager.Rewrite(p.Html ?? "", Importer.WpBaseUrl, "__GHOST_URL__");
|
|
|
|
|
internalLinks += rewritten.Replaced;
|
|
|
|
|
return new GhostPost
|
|
|
|
|
{
|
|
|
|
|
Id = p.Id, Title = p.Title, Slug = p.Slug, Html = rewritten.Html, Markdown = p.Markdown,
|
|
|
|
|
FeatureImage = p.FeatureImage, Status = p.Status, CreatedAt = p.CreatedAt, PublishedAt = p.PublishedAt
|
|
|
|
|
};
|
|
|
|
|
}).ToList();
|
|
|
|
|
if (internalLinks > 0)
|
|
|
|
|
Console.WriteLine($" {internalLinks} interne(r) Link(s) auf Ghost umgeschrieben");
|
|
|
|
|
|
2026-09-20 08:31:23 +02:00
|
|
|
string jsonString = JsonSerializer.Serialize(new GhostRoot
|
|
|
|
|
{
|
2026-10-14 19:12:29 +02:00
|
|
|
Db = new List<GhostDb> { new GhostDb { Data = new GhostData { Posts = exportPosts } } }
|
2026-09-20 08:31:23 +02:00
|
|
|
}, new JsonSerializerOptions
|
|
|
|
|
{
|
|
|
|
|
WriteIndented = true,
|
|
|
|
|
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
string outputDir = Path.GetDirectoryName(outputPath) ?? BaseDir;
|
|
|
|
|
if (!Directory.Exists(outputDir))
|
|
|
|
|
Directory.CreateDirectory(outputDir);
|
|
|
|
|
|
|
|
|
|
using (var zipStream = new FileStream(outputPath, FileMode.Create))
|
|
|
|
|
using (var archive = new ZipArchive(zipStream, ZipArchiveMode.Create, true))
|
|
|
|
|
{
|
|
|
|
|
var jsonEntry = archive.CreateEntry("import.json");
|
|
|
|
|
using (var writer = new StreamWriter(jsonEntry.Open()))
|
|
|
|
|
{
|
|
|
|
|
await writer.WriteAsync(jsonString);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Directory.Exists(MarkdownDir))
|
|
|
|
|
{
|
|
|
|
|
foreach (string mdFile in Directory.GetFiles(MarkdownDir, "*.md", SearchOption.AllDirectories))
|
|
|
|
|
{
|
|
|
|
|
string relativeMdPath = Path.GetFileName(mdFile);
|
|
|
|
|
var mdEntry = archive.CreateEntry($"content/{relativeMdPath}");
|
|
|
|
|
using (var entryStream = mdEntry.Open())
|
|
|
|
|
using (var fileStream = File.OpenRead(mdFile))
|
|
|
|
|
{
|
|
|
|
|
await fileStream.CopyToAsync(entryStream);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var file in ImageManager.CachedFiles)
|
|
|
|
|
{
|
|
|
|
|
string fullLocalPath = Path.Combine(Path.Combine(BaseDir, "images"), file.RelativePath);
|
|
|
|
|
if (File.Exists(fullLocalPath))
|
|
|
|
|
{
|
|
|
|
|
var fileEntry = archive.CreateEntry($"content/images/{file.RelativePath}");
|
|
|
|
|
using (var entryStream = fileEntry.Open())
|
|
|
|
|
using (var fileStream = File.OpenRead(fullLocalPath))
|
|
|
|
|
{
|
|
|
|
|
await fileStream.CopyToAsync(entryStream);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-10-14 19:12:29 +02:00
|
|
|
|
|
|
|
|
// Videos unkomprimiert ablegen (MP4 lässt sich nicht weiter packen)
|
|
|
|
|
foreach (var file in MediaManager.CachedFiles)
|
|
|
|
|
{
|
|
|
|
|
if (File.Exists(file.LocalPath))
|
|
|
|
|
{
|
|
|
|
|
var fileEntry = archive.CreateEntry($"content/media/{file.RelativePath}", CompressionLevel.NoCompression);
|
|
|
|
|
using (var entryStream = fileEntry.Open())
|
|
|
|
|
using (var fileStream = File.OpenRead(file.LocalPath))
|
|
|
|
|
{
|
|
|
|
|
await fileStream.CopyToAsync(entryStream);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-09-20 08:31:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Console.WriteLine();
|
|
|
|
|
Console.WriteLine("=========================================");
|
|
|
|
|
Console.WriteLine($" Ghost ZIP erstellt!");
|
|
|
|
|
Console.WriteLine($" Beiträge: {posts.Count}");
|
|
|
|
|
Console.WriteLine($" Bilder: {ImageManager.CachedFiles.Count} Dateien");
|
2026-10-14 19:12:29 +02:00
|
|
|
Console.WriteLine($" Videos: {MediaManager.CachedFiles.Count} Dateien");
|
2026-09-20 08:31:23 +02:00
|
|
|
Console.WriteLine($" Ausgabe: {outputPath}");
|
|
|
|
|
Console.WriteLine("=========================================");
|
|
|
|
|
}
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
{
|
|
|
|
|
Console.WriteLine($"\nFehler beim Erstellen der ZIP-Datei: {ex.Message}");
|
|
|
|
|
Console.WriteLine($"Stack Trace: {ex.StackTrace}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|