using SixLabors.ImageSharp; using SixLabors.ImageSharp.Processing; using System.Diagnostics.Metrics; namespace wp2ghost { // ============================================================================= // ImageManager — Bilder herunterladen, cachen, lokal verwalten // ============================================================================= static class ImageManager { private static readonly HttpClient httpClient = new(); private static Dictionary Cache = new(); private static List<(string RelativePath, string LocalPath)> FilesToZip = new(); private static string LocalImageDir = ""; private static string CachePath = ""; public static IReadOnlyList<(string RelativePath, string LocalPath)> CachedFiles => FilesToZip; public static bool TryGetRelativePath(string url, out string relativePath) { if (Cache.TryGetValue(url, out var cached)) { relativePath = cached.RelativePath; return true; } relativePath = ""; return false; } public static void Init(string baseDir) { LocalImageDir = Path.Combine(baseDir, "images"); CachePath = Path.Combine(baseDir, "imagecache.txt"); if (!Directory.Exists(LocalImageDir)) Directory.CreateDirectory(LocalImageDir); LoadCache(); } public static string ImageContainerPath => LocalImageDir; public static void SaveCache() { var lines = new List(); foreach (var kvp in Cache) lines.Add($"{kvp.Key}|{kvp.Value.RelativePath}|{kvp.Value.LocalPath}"); File.WriteAllLines(CachePath, lines); } public static void ClearAll() { if (Directory.Exists(LocalImageDir)) { Directory.Delete(LocalImageDir, true); Directory.CreateDirectory(LocalImageDir); } Cache.Clear(); FilesToZip.Clear(); SaveCache(); Console.WriteLine("Bilder wurden lokal gelöscht."); } public static void ShowInfo() { if (Cache.Count > 0) { Console.WriteLine("\nLokal gespeicherte Bilder:"); foreach (var kvp in Cache.Take(20)) Console.WriteLine($" {kvp.Key} -> images/{kvp.Value.RelativePath}"); if (Cache.Count > 20) Console.WriteLine($" ... und {Cache.Count - 20} weitere"); } } public static bool IsMainImage(string url) { if (string.IsNullOrEmpty(url)) return false; try { var uri = new Uri(url); string fileName = Path.GetFileName(uri.LocalPath); // WordPress-Sizes: -300x200, -scaled, -1024x768 etc. if (System.Text.RegularExpressions.Regex.IsMatch(fileName, @"-\d+x\d+(?=\.\w+$)")) return false; if (fileName.Contains("-scaled")) return false; return true; } catch { return false; } } public static async Task<(string RelativePath, string LocalPath)?> DownloadAsync(string imageUrl, DateTime? postDate) { if (string.IsNullOrEmpty(imageUrl) || !Uri.IsWellFormedUriString(imageUrl, UriKind.Absolute)) return null; if (Cache.TryGetValue(imageUrl, out var cachedFile)) { if (File.Exists(cachedFile.LocalPath)) return cachedFile; Cache.Remove(imageUrl); } try { string fileName = Path.GetFileName(new Uri(imageUrl).AbsolutePath); string urlHash = GetHashCode(imageUrl); var datePrefix = DateTime.Now; string datePath = $"{datePrefix:yyyy}/{datePrefix:MM}"; var localPath = Path.Combine(LocalImageDir, datePath); if (!string.IsNullOrEmpty(localPath) && !Directory.Exists(localPath)) Directory.CreateDirectory(localPath); var counter = 1 + new DirectoryInfo(localPath).GetFiles().Length; var pDate = postDate ?? DateTime.Now; string uniqueFileName = $"{pDate:yyyymmdd}_{counter}{Path.GetExtension(fileName)}"; string relativePath = $"{datePath}/{uniqueFileName}"; string fallBackPath = $"{datePath}/{uniqueFileName}"; localPath = Path.Combine(LocalImageDir, relativePath); fallBackPath = Path.Combine(LocalImageDir, fallBackPath); if (File.Exists(fallBackPath)) { File.Move(fallBackPath, localPath); Console.WriteLine($" [Bild] Bereits vorhanden: {relativePath}"); } else if (!File.Exists(localPath)) { byte[] imageBytes = await httpClient.GetByteArrayAsync(imageUrl); await File.WriteAllBytesAsync(localPath, imageBytes); Console.WriteLine($" [Bild] Heruntergeladen: {relativePath}"); } else { Console.WriteLine($" [Bild] Bereits vorhanden: {relativePath}"); } ResizeImage(localPath); var fileResult = (relativePath, localPath); Cache[imageUrl] = fileResult; FilesToZip.Add(fileResult); return fileResult; } catch (Exception ex) { Console.WriteLine($" [Bild-Fehler] Konnte {imageUrl} nicht laden: {ex.Message}"); return null; } } private static void ResizeImage(string localPath) { const int maxSize = 1024; try { using var image = Image.Load(localPath); int width = image.Width; int height = image.Height; int longEdge = Math.Max(width, height); if (longEdge <= maxSize) return; int newWidth, newHeight; if (width >= height) { newWidth = maxSize; newHeight = (int)Math.Round(height * ((double)maxSize / width)); } else { newHeight = maxSize; newWidth = (int)Math.Round(width * ((double)maxSize / height)); } image.Mutate(x => x.Resize(newWidth, newHeight)); image.Save(localPath); Console.WriteLine($" [Bild] Angepasst: {width}x{height} → {newWidth}x{newHeight}"); } catch (Exception ex) { Console.WriteLine($" [Bild-Warnung] Resize fehlgeschlagen für {Path.GetFileName(localPath)}: {ex.Message}"); } } private static string GetHashCode(string input) { unchecked { int hash = 17; foreach (char c in input) hash = hash * 23 + c; return hash.ToString("x8"); } } private static void LoadCache() { if (!File.Exists(CachePath)) return; try { var lines = File.ReadAllLines(CachePath); foreach (var line in lines) { var parts = line.Split('|'); if (parts.Length == 3) Cache[parts[0]] = (parts[1], parts[2]); } } catch (Exception ex) { Console.WriteLine($"Fehler beim Laden des Bild-Caches: {ex.Message}"); } } } }