diff --git a/.github/workflows/reusable-hugo-workflow.yml b/.github/workflows/reusable-hugo-workflow.yml index b6f0143..44d7595 100644 --- a/.github/workflows/reusable-hugo-workflow.yml +++ b/.github/workflows/reusable-hugo-workflow.yml @@ -5,7 +5,7 @@ on: inputs: hugo_version: type: string - default: '0.140.0' + default: '0.142.0' required: false base_url: type: string diff --git a/adminEditor/main.go b/adminEditor/main.go index 240c66d..6ec43f8 100644 --- a/adminEditor/main.go +++ b/adminEditor/main.go @@ -64,6 +64,7 @@ func NewFluxClient(apiKey string) *FluxClient { // GenerateLandscapeImage generates a landscape image using the FLUX API func (c *FluxClient) GenerateLandscapeImage(prompt string, outputFile string) error { + log.Println("GenerateLandscapeImage: Preparing request") // Prepare the request request := FluxRequest{ Prompt: prompt, @@ -74,12 +75,14 @@ func (c *FluxClient) GenerateLandscapeImage(prompt string, outputFile string) er // Convert request to JSON requestBody, err := json.Marshal(request) if err != nil { + log.Printf("GenerateLandscapeImage: Error marshaling request: %v", err) return fmt.Errorf("error marshaling request: %w", err) } // Create HTTP request req, err := http.NewRequest("POST", c.baseURL, bytes.NewBuffer(requestBody)) if err != nil { + log.Printf("GenerateLandscapeImage: Error creating request: %v", err) return fmt.Errorf("error creating request: %w", err) } @@ -88,8 +91,10 @@ func (c *FluxClient) GenerateLandscapeImage(prompt string, outputFile string) er req.Header.Set("Api-Key", c.apiKey) // Send request + log.Println("GenerateLandscapeImage: Sending request to FLUX API") resp, err := c.httpClient.Do(req) if err != nil { + log.Printf("GenerateLandscapeImage: Error sending request: %v", err) return fmt.Errorf("error sending request: %w", err) } defer resp.Body.Close() @@ -97,36 +102,43 @@ func (c *FluxClient) GenerateLandscapeImage(prompt string, outputFile string) er // Read response body body, err := io.ReadAll(resp.Body) if err != nil { + log.Printf("GenerateLandscapeImage: Error reading response: %v", err) return fmt.Errorf("error reading response: %w", err) } // Check for successful status code if resp.StatusCode != http.StatusOK { + log.Printf("GenerateLandscapeImage: API request failed with status %d: %s", resp.StatusCode, string(body)) return fmt.Errorf("API request failed with status %d: %s", resp.StatusCode, string(body)) } // Parse response var fluxResponse FluxResponse if err := json.Unmarshal(body, &fluxResponse); err != nil { + log.Printf("GenerateLandscapeImage: Error parsing response: %v", err) return fmt.Errorf("error parsing response: %w", err) } // Check for API error if fluxResponse.ErrorMessage != "" { + log.Printf("GenerateLandscapeImage: API error: %s", fluxResponse.ErrorMessage) return fmt.Errorf("API error: %s", fluxResponse.ErrorMessage) } // Decode base64 image imageData, err := base64.StdEncoding.DecodeString(fluxResponse.ImageData) if err != nil { + log.Printf("GenerateLandscapeImage: Error decoding image data: %v", err) return fmt.Errorf("error decoding image data: %w", err) } // Save image to file if err := os.WriteFile(outputFile, imageData, 0644); err != nil { + log.Printf("GenerateLandscapeImage: Error saving image: %v", err) return fmt.Errorf("error saving image: %w", err) } + log.Printf("GenerateLandscapeImage: Image successfully saved to %s", outputFile) return nil } @@ -134,11 +146,13 @@ var config Config func main() { // Load configuration + log.Println("main: Loading configuration") loadConfig() // Serve static files from the "static" directory fs := http.FileServer(http.Dir("static")) http.Handle("/", fs) + log.Println("main: Serving static files from /static") // API endpoints http.HandleFunc("/api/config", handleConfig) @@ -160,6 +174,7 @@ func main() { httpSwagger.DocExpansion("none"), httpSwagger.DomID("swagger-ui"), )) + log.Println("main: Swagger UI configured") // Determine the address to listen on addr := fmt.Sprintf(":%d", config.Server.Port) @@ -173,64 +188,74 @@ func main() { } // Start the server + log.Println("main: Starting the server") log.Fatal(http.ListenAndServe(addr, nil)) } func loadConfig() { file, err := ioutil.ReadFile("config.json") if err != nil { - log.Fatal("Error reading config file:", err) + log.Fatalf("loadConfig: Error reading config file: %v", err) } err = json.Unmarshal(file, &config) if err != nil { - log.Fatal("Error parsing config file:", err) + log.Fatalf("loadConfig: Error parsing config file: %v", err) } // Set default values if not specified if config.Server.Port == 0 { config.Server.Port = 8080 + log.Println("loadConfig: Server Port not set, defaulting to 8080") } if config.Server.GermanFolder == "" { config.Server.GermanFolder = "../content/de/blog" + log.Println("loadConfig: GermanFolder not set, defaulting to ../content/de/blog") } if config.Server.EnglishFolder == "" { config.Server.EnglishFolder = "../content/en/blog" + log.Println("loadConfig: EnglishFolder not set, defaulting to ../content/en/blog") } // Convert relative paths to absolute paths absGermanFolder, err := filepath.Abs(config.Server.GermanFolder) if err != nil { - log.Fatalf("Error converting relative path to absolute path for German folder: %v", err) + log.Fatalf("loadConfig: Error converting GermanFolder to absolute path: %v", err) } config.Server.GermanFolder = absGermanFolder + log.Printf("loadConfig: GermanFolder set to %s", absGermanFolder) absEnglishFolder, err := filepath.Abs(config.Server.EnglishFolder) if err != nil { - log.Fatalf("Error converting relative path to absolute path for English folder: %v", err) + log.Fatalf("loadConfig: Error converting EnglishFolder to absolute path: %v", err) } config.Server.EnglishFolder = absEnglishFolder + log.Printf("loadConfig: EnglishFolder set to %s", absEnglishFolder) } func handleConfig(w http.ResponseWriter, r *http.Request) { + log.Println("handleConfig: Handling config request") w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(config) } func handleSave(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { + log.Printf("handleSave: Method not allowed - %s", r.Method) http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } filename := r.URL.Query().Get("file") if filename == "" { + log.Println("handleSave: Filename is required") http.Error(w, "Filename is required", http.StatusBadRequest) return } content, err := ioutil.ReadAll(r.Body) if err != nil { + log.Printf("handleSave: Error reading request body: %v", err) http.Error(w, "Error reading request body", http.StatusInternalServerError) return } @@ -238,16 +263,19 @@ func handleSave(w http.ResponseWriter, r *http.Request) { fullPath := getFullPath(filename) err = ioutil.WriteFile(fullPath, content, 0644) if err != nil { + log.Printf("handleSave: Error saving file %s: %v", fullPath, err) http.Error(w, "Error saving file", http.StatusInternalServerError) return } + log.Printf("handleSave: Successfully saved file %s", fullPath) w.WriteHeader(http.StatusOK) } func handleLoad(w http.ResponseWriter, r *http.Request) { filename := r.URL.Query().Get("file") if filename == "" { + log.Println("handleLoad: Filename is required") http.Error(w, "Filename is required", http.StatusBadRequest) return } @@ -256,22 +284,27 @@ func handleLoad(w http.ResponseWriter, r *http.Request) { content, err := ioutil.ReadFile(fullPath) if err != nil { if os.IsNotExist(err) { + log.Printf("handleLoad: File not found: %s", fullPath) http.Error(w, "File not found", http.StatusNotFound) } else { + log.Printf("handleLoad: Error reading file %s: %v", fullPath, err) http.Error(w, "Error reading file", http.StatusInternalServerError) } return } + log.Printf("handleLoad: Successfully loaded file %s", fullPath) w.Header().Set("Content-Type", "text/plain") w.Write(content) } func handleList(w http.ResponseWriter, r *http.Request) { + log.Println("handleList: Handling list request") files := make(map[string][]string) germanFiles, err := listFiles(config.Server.GermanFolder) if err != nil { + log.Printf("handleList: Error reading German directory: %v", err) http.Error(w, "Error reading German directory", http.StatusInternalServerError) return } @@ -279,31 +312,32 @@ func handleList(w http.ResponseWriter, r *http.Request) { englishFiles, err := listFiles(config.Server.EnglishFolder) if err != nil { + log.Printf("handleList: Error reading English directory: %v", err) http.Error(w, "Error reading English directory", http.StatusInternalServerError) return } files["en"] = englishFiles - files["en"] = englishFiles - w.Header().Set("Content-Type", "application/json") lang := r.URL.Query().Get("lang") switch lang { case "de": + log.Println("handleList: Responding with German files") json.NewEncoder(w).Encode(germanFiles) case "en": + log.Println("handleList: Responding with English files") json.NewEncoder(w).Encode(englishFiles) default: + log.Println("handleList: Responding with all files") json.NewEncoder(w).Encode(files) } - - w.Header().Set("Content-Type", "application/json") - } func handleMediaList(w http.ResponseWriter, r *http.Request) { + log.Println("handleMediaList: Handling media list request") files, err := ioutil.ReadDir(config.Server.MediaFolder) if err != nil { + log.Printf("handleMediaList: Error reading media directory: %v", err) http.Error(w, "Error reading media directory", http.StatusInternalServerError) return } @@ -315,12 +349,14 @@ func handleMediaList(w http.ResponseWriter, r *http.Request) { } } + log.Printf("handleMediaList: Found %d media files", len(mediaFiles)) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(mediaFiles) } func handleProcessMedia(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { + log.Printf("handleProcessMedia: Method not allowed - %s", r.Method) http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } @@ -330,12 +366,15 @@ func handleProcessMedia(w http.ResponseWriter, r *http.Request) { NewName string `json:"newName"` } if err := json.NewDecoder(r.Body).Decode(&request); err != nil { + log.Printf("handleProcessMedia: Invalid request body: %v", err) http.Error(w, "Invalid request body", http.StatusBadRequest) return } + log.Printf("handleProcessMedia: Processing media file: %s with new name: %s", request.File, request.NewName) newFileName, err := processMediaFile(request) if err != nil { + log.Printf("handleProcessMedia: Error processing media file: %v", err) http.Error(w, err.Error(), http.StatusInternalServerError) return } @@ -346,53 +385,105 @@ func handleProcessMedia(w http.ResponseWriter, r *http.Request) { Filename: newFileName, } + log.Printf("handleProcessMedia: Successfully processed media file: %s", newFileName) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(response) } func handleCreatePost(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { + log.Printf("handleCreatePost: Method not allowed - %s", r.Method) http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } + log.Println("handleCreatePost: Received request to create a new post") + + // Read the raw request body first for debugging + bodyBytes, err := io.ReadAll(r.Body) + if err != nil { + log.Printf("handleCreatePost: Error reading request body: %v", err) + http.Error(w, "Error reading request body", http.StatusBadRequest) + return + } + r.Body = io.NopCloser(bytes.NewBuffer(bodyBytes)) // Restore the body for later use + + // Log raw request for debugging + log.Printf("handleCreatePost: Raw request body: %s", string(bodyBytes)) + var request NewPostRequest if err := json.NewDecoder(r.Body).Decode(&request); err != nil { - http.Error(w, "Invalid request body", http.StatusBadRequest) + log.Printf("handleCreatePost: Invalid request body: %v, Raw body: %s", err, string(bodyBytes)) + http.Error(w, fmt.Sprintf("Invalid request body: %v", err), http.StatusBadRequest) return } - // Validate required fields - if request.Title == "" || request.Date == "" { - http.Error(w, "Title and date are required", http.StatusBadRequest) + log.Printf("handleCreatePost: Decoded request: %+v", request) + + // Validate required fields with more specific logging + if request.Title == "" { + log.Println("handleCreatePost: Title is missing") + http.Error(w, "Title is required", http.StatusBadRequest) return } + if request.Date == "" { + log.Println("handleCreatePost: Date is missing") + http.Error(w, "Date is required", http.StatusBadRequest) + return + } + log.Printf("handleCreatePost: Validation passed - Title: %s, Date: %s", request.Title, request.Date) // Create filename from title filename := createSlug(request.Title) + ".md" + log.Printf("handleCreatePost: Generated filename: %s from title: %s", filename, request.Title) + if request.Slug == "" { request.Slug = slug.Make(request.Title) + log.Printf("handleCreatePost: Generated slug: %s from title: %s", request.Slug, request.Title) } + // Handle Thumbnail Creation with more detailed logging + log.Printf("handleCreatePost: Starting thumbnail handling - LocalFile: %s, URL: %s", + request.Thumbnail.LocalFile, request.Thumbnail.URL) + if request.Thumbnail.LocalFile == "" && request.Thumbnail.URL == "" { newFileName := request.Slug + ".jpg" destFile := filepath.Join(config.Server.AssetFolder, newFileName) - // Check if file exists + log.Printf("handleCreatePost: Thumbnail destination file: %s (AssetFolder: %s)", + destFile, config.Server.AssetFolder) + + // Check if AssetFolder exists + if _, err := os.Stat(config.Server.AssetFolder); os.IsNotExist(err) { + log.Printf("handleCreatePost: AssetFolder does not exist: %s", config.Server.AssetFolder) + if err := os.MkdirAll(config.Server.AssetFolder, 0755); err != nil { + log.Printf("handleCreatePost: Error creating AssetFolder: %v", err) + http.Error(w, "Error creating asset folder: "+err.Error(), http.StatusInternalServerError) + return + } + log.Printf("handleCreatePost: Created AssetFolder: %s", config.Server.AssetFolder) + } + + // Check if thumbnail file exists if _, err := os.Stat(destFile); err == nil { - fmt.Printf("File exists already: %s\n", destFile) + log.Printf("handleCreatePost: Thumbnail file already exists: %s", destFile) } else { + log.Printf("handleCreatePost: Creating thumbnail using ImagePig with title: %s", request.Title) err := createImageWithImagePig(request.Title, destFile) if err != nil { - http.Error(w, "Error creating thumbnail: "+err.Error(), http.StatusInternalServerError) + log.Printf("handleCreatePost: Error creating thumbnail: %v", err) + http.Error(w, fmt.Sprintf("Error creating thumbnail: %v", err), http.StatusInternalServerError) return } + log.Printf("handleCreatePost: Successfully created thumbnail: %s", destFile) } request.Thumbnail.URL = "/img/blog/" + newFileName + log.Printf("handleCreatePost: Set Thumbnail URL: %s", request.Thumbnail.URL) } + // Process Local Thumbnail File if request.Thumbnail.LocalFile != "" && request.Thumbnail.URL == "" { + log.Printf("handleCreatePost: Processing local thumbnail file: %s", request.Thumbnail.LocalFile) - // Create a variable of the struct type var reqMediaFile struct { File string `json:"file"` NewName string `json:"newName"` @@ -400,21 +491,16 @@ func handleCreatePost(w http.ResponseWriter, r *http.Request) { reqMediaFile.File = request.Thumbnail.LocalFile reqMediaFile.NewName = request.Slug - // Log the processing of the media file - log.Printf("Processing media file: %s\n", request.Thumbnail.LocalFile) newFileName, err := processMediaFile(reqMediaFile) if err != nil { + log.Printf("handleCreatePost: Error processing media file: %v", err) http.Error(w, err.Error(), http.StatusInternalServerError) - return } - // Log the result of the media file processing - log.Printf("Processed media file: %s -> %s\n", request.Thumbnail.LocalFile, newFileName) - + log.Printf("handleCreatePost: Processed media file from %s to %s", request.Thumbnail.LocalFile, newFileName) request.Thumbnail.URL = "/img/blog/" + newFileName - } // Determine the target folder based on language @@ -425,56 +511,95 @@ func handleCreatePost(w http.ResponseWriter, r *http.Request) { case "en": targetFolder = config.Server.EnglishFolder default: - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusBadRequest) - json.NewEncoder(w).Encode(map[string]string{"error": "Invalid language"}) + log.Printf("handleCreatePost: Invalid language specified: %s", request.Language) + http.Error(w, "Invalid language", http.StatusBadRequest) return } + log.Printf("handleCreatePost: Target folder set to: %s", targetFolder) - // Generate markdown content + // Generate markdown content with logging + log.Printf("handleCreatePost: Generating markdown content for post: %s", request.Title) content := generateMarkdownContent(request) + log.Printf("handleCreatePost: Generated markdown content length: %d bytes", len(content)) + + // Ensure target folder exists + if _, err := os.Stat(targetFolder); os.IsNotExist(err) { + log.Printf("handleCreatePost: Target folder does not exist: %s", targetFolder) + if err := os.MkdirAll(targetFolder, 0755); err != nil { + log.Printf("handleCreatePost: Error creating target folder: %v", err) + http.Error(w, fmt.Sprintf("Error creating target folder: %v", err), http.StatusInternalServerError) + return + } + log.Printf("handleCreatePost: Created target folder: %s", targetFolder) + } - // Save the file + // Save the file with detailed error logging fullPath := filepath.Join(targetFolder, filename) + log.Printf("handleCreatePost: Attempting to save file to: %s", fullPath) if err := ioutil.WriteFile(fullPath, []byte(content), 0644); err != nil { - http.Error(w, "Error saving file", http.StatusInternalServerError) + log.Printf("handleCreatePost: Error saving file %s: %v (Content length: %d)", fullPath, err, len(content)) + http.Error(w, fmt.Sprintf("Error saving file: %v", err), http.StatusInternalServerError) return } + log.Printf("handleCreatePost: Successfully saved post to %s (Content length: %d)", fullPath, len(content)) - // Update tags and categories in config - updateTagsAndCategories(request.Tags, request.Categories) + // Update tags and categories in config with detailed logging + log.Printf("handleCreatePost: Updating tags (%d) and categories (%d)", len(request.Tags), len(request.Categories)) + if err := updateTagsAndCategories(request.Tags, request.Categories); err != nil { + log.Printf("handleCreatePost: Error updating tags and categories: %v (Tags: %v, Categories: %v)", + err, request.Tags, request.Categories) + http.Error(w, fmt.Sprintf("Error updating tags and categories: %v", err), http.StatusInternalServerError) + return + } + log.Printf("handleCreatePost: Successfully updated %d tags and %d categories", len(request.Tags), len(request.Categories)) + // Prepare and send response with proper error handling w.Header().Set("Content-Type", "application/json") - json.NewEncoder(w).Encode(map[string]string{"filename": filename}) + response := map[string]string{ + "filename": filename, + "path": fullPath, + } + log.Printf("handleCreatePost: Preparing response: %+v", response) + + if err := json.NewEncoder(w).Encode(response); err != nil { + log.Printf("handleCreatePost: Error encoding response: %v", err) + http.Error(w, fmt.Sprintf("Error encoding response: %v", err), http.StatusInternalServerError) + return + } + log.Printf("handleCreatePost: Successfully completed post creation: %s", filename) } func handleGetTags(w http.ResponseWriter, r *http.Request) { + log.Println("handleGetTags: Handling get tags request") tags, err := getAllTags() if err != nil { + log.Printf("handleGetTags: Error reading tags: %v", err) http.Error(w, "Error reading tags", http.StatusInternalServerError) return } + log.Printf("handleGetTags: Retrieved %d tags", len(tags)) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(tags) } func handleGetCategories(w http.ResponseWriter, r *http.Request) { + log.Println("handleGetCategories: Handling get categories request") categories, err := getAllCategories() if err != nil { + log.Printf("handleGetCategories: Error reading categories: %v", err) http.Error(w, "Error reading categories", http.StatusInternalServerError) return } + log.Printf("handleGetCategories: Retrieved %d categories", len(categories)) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(categories) } func createSlug(title string) string { - // Convert to lowercase and replace spaces with hyphens slug := strings.ToLower(title) slug = strings.ReplaceAll(slug, " ", "-") - // Remove special characters slug = regexp.MustCompile(`[^a-z0-9-]`).ReplaceAllString(slug, "") return slug } @@ -495,7 +620,7 @@ func generateMarkdownContent(post NewPostRequest) string { // Convert date string to time.Time date, err := time.Parse("2006-01-02T15:04", post.Date) if err != nil { - log.Printf("Error parsing date: %v", err) + log.Printf("generateMarkdownContent: Error parsing date: %v", err) date = time.Now() } // Convert date to UTC @@ -534,63 +659,74 @@ func generateMarkdownContent(post NewPostRequest) string { // getAllTags reads and returns all tags from the tags data file func getAllTags() ([]Tag, error) { - // Read tags from a JSON file + log.Println("getAllTags: Reading tags from data/tags.json") file, err := ioutil.ReadFile("data/tags.json") if err != nil { if os.IsNotExist(err) { - // Return empty array if file doesn't exist + log.Println("getAllTags: tags.json does not exist, returning empty slice") return []Tag{}, nil } + log.Printf("getAllTags: Error reading tags.json: %v", err) return nil, err } var tagsData TagsData err = json.Unmarshal(file, &tagsData) if err != nil { + log.Printf("getAllTags: Error unmarshaling tags.json: %v", err) return nil, err } + log.Printf("getAllTags: Retrieved %d tags", len(tagsData.Tags)) return tagsData.Tags, nil } // getAllCategories reads and returns all categories from the categories data file func getAllCategories() ([]Category, error) { - // Read categories from a JSON file + log.Println("getAllCategories: Reading categories from data/categories.json") file, err := ioutil.ReadFile("data/categories.json") if err != nil { if os.IsNotExist(err) { - // Return empty array if file doesn't exist + log.Println("getAllCategories: categories.json does not exist, returning empty slice") return []Category{}, nil } + log.Printf("getAllCategories: Error reading categories.json: %v", err) return nil, err } var categoriesData CategoriesData err = json.Unmarshal(file, &categoriesData) if err != nil { + log.Printf("getAllCategories: Error unmarshaling categories.json: %v", err) return nil, err } + log.Printf("getAllCategories: Retrieved %d categories", len(categoriesData.Categories)) return categoriesData.Categories, nil } // updateTagsAndCategories updates the tags and categories data files with new entries func updateTagsAndCategories(newTags []string, newCategories []string) error { + log.Println("updateTagsAndCategories: Updating tags and categories") // Update tags if err := updateTags(newTags); err != nil { + log.Printf("updateTagsAndCategories: Error updating tags: %v", err) return err } // Update categories if err := updateCategories(newCategories); err != nil { + log.Printf("updateTagsAndCategories: Error updating categories: %v", err) return err } + log.Println("updateTagsAndCategories: Successfully updated tags and categories") return nil } // updateTags updates the tags data file with new tags func updateTags(newTags []string) error { + log.Println("updateTags: Updating tags") existingTags, err := getAllTags() if err != nil { return err @@ -606,16 +742,19 @@ func updateTags(newTags []string) error { for _, newTag := range newTags { if tag, exists := tagMap[newTag]; exists { tag.Count++ + log.Printf("updateTags: Incremented count for existing tag: %s (New count: %d)", newTag, tag.Count) } else { existingTags = append(existingTags, Tag{ Name: newTag, Count: 1, }) + log.Printf("updateTags: Added new tag: %s", newTag) } } // Create data directory if it doesn't exist if err := os.MkdirAll("data", 0755); err != nil { + log.Printf("updateTags: Error creating data directory: %v", err) return err } @@ -623,14 +762,23 @@ func updateTags(newTags []string) error { tagsData := TagsData{Tags: existingTags} jsonData, err := json.MarshalIndent(tagsData, "", " ") if err != nil { + log.Printf("updateTags: Error marshaling tags data: %v", err) + return err + } + + err = ioutil.WriteFile("data/tags.json", jsonData, 0644) + if err != nil { + log.Printf("updateTags: Error writing tags.json: %v", err) return err } - return ioutil.WriteFile("data/tags.json", jsonData, 0644) + log.Println("updateTags: Successfully updated tags.json") + return nil } // updateCategories updates the categories data file with new categories func updateCategories(newCategories []string) error { + log.Println("updateCategories: Updating categories") existingCategories, err := getAllCategories() if err != nil { return err @@ -646,16 +794,19 @@ func updateCategories(newCategories []string) error { for _, newCategory := range newCategories { if category, exists := categoryMap[newCategory]; exists { category.Count++ + log.Printf("updateCategories: Incremented count for existing category: %s (New count: %d)", newCategory, category.Count) } else { existingCategories = append(existingCategories, Category{ Name: newCategory, Count: 1, }) + log.Printf("updateCategories: Added new category: %s", newCategory) } } // Create data directory if it doesn't exist if err := os.MkdirAll("data", 0755); err != nil { + log.Printf("updateCategories: Error creating data directory: %v", err) return err } @@ -663,67 +814,92 @@ func updateCategories(newCategories []string) error { categoriesData := CategoriesData{Categories: existingCategories} jsonData, err := json.MarshalIndent(categoriesData, "", " ") if err != nil { + log.Printf("updateCategories: Error marshaling categories data: %v", err) return err } - return ioutil.WriteFile("data/categories.json", jsonData, 0644) + err = ioutil.WriteFile("data/categories.json", jsonData, 0644) + if err != nil { + log.Printf("updateCategories: Error writing categories.json: %v", err) + return err + } + + log.Println("updateCategories: Successfully updated categories.json") + return nil } +// processMediaFile processes the media file and returns the new filename func processMediaFile(request struct { File string `json:"file"` NewName string `json:"newName"` }) (string, error) { + log.Printf("processMediaFile: Processing file %s with new name %s", request.File, request.NewName) sourceFile := filepath.Join(config.Server.MediaFolder, request.File) ext := filepath.Ext(request.File) newFileName := request.NewName + ext destFile := filepath.Join(config.Server.AssetFolder, newFileName) + log.Printf("processMediaFile: Source file: %s, Destination file: %s", sourceFile, destFile) + // Open the source image src, err := imaging.Open(sourceFile) if err != nil { + log.Printf("processMediaFile: Error opening source image: %v", err) return "", fmt.Errorf("error opening source image: %w", err) } + log.Println("processMediaFile: Source image opened successfully") // Get the dimensions of the source image srcWidth := src.Bounds().Dx() srcHeight := src.Bounds().Dy() + log.Printf("processMediaFile: Source image dimensions: %dx%d", srcWidth, srcHeight) // Calculate the new height to maintain the aspect ratio newHeight := (config.Server.ImageResize.MaxWidth * srcHeight) / srcWidth + log.Printf("processMediaFile: Calculated new height: %d", newHeight) // Resize the image var resized image.Image if config.Server.ImageResize.Method == "fit" { resized = imaging.Fit(src, config.Server.ImageResize.MaxWidth, newHeight, imaging.Lanczos) + log.Println("processMediaFile: Image resized using 'fit' method") } else { resized = imaging.Fill(src, config.Server.ImageResize.MaxWidth, newHeight, imaging.Center, imaging.Lanczos) + log.Println("processMediaFile: Image resized using 'fill' method") } // Save the resized image err = imaging.Save(resized, destFile) if err != nil { + log.Printf("processMediaFile: Error saving resized image: %v", err) return "", fmt.Errorf("error saving resized image: %w", err) } + log.Printf("processMediaFile: Resized image saved to %s", destFile) // Create and save thumbnail var thumbnail image.Image if config.Server.ThumbnailResize.Method == "fit" { thumbnail = imaging.Fit(src, config.Server.ThumbnailResize.MaxWidth, newHeight, imaging.Lanczos) + log.Println("processMediaFile: Thumbnail resized using 'fit' method") } else { thumbnail = imaging.Fill(src, config.Server.ThumbnailResize.MaxWidth, newHeight, imaging.Center, imaging.Lanczos) + log.Println("processMediaFile: Thumbnail resized using 'fill' method") } thumbnailFile := filepath.Join(config.Server.AssetFolder, "thumb_"+newFileName) err = imaging.Save(thumbnail, thumbnailFile) if err != nil { + log.Printf("processMediaFile: Error saving thumbnail: %v", err) return "", fmt.Errorf("error saving thumbnail: %w", err) } + log.Printf("processMediaFile: Thumbnail saved to %s", thumbnailFile) return newFileName, nil } func handleUploadMediaFolder(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { + log.Printf("handleUploadMediaFolder: Method not allowed - %s", r.Method) http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } @@ -731,12 +907,14 @@ func handleUploadMediaFolder(w http.ResponseWriter, r *http.Request) { // Parse the multipart form data with a 32MB limit err := r.ParseMultipartForm(32 << 20) if err != nil { + log.Printf("handleUploadMediaFolder: Error parsing form data: %v", err) http.Error(w, "Error parsing form data", http.StatusBadRequest) return } file, header, err := r.FormFile("file") if err != nil { + log.Printf("handleUploadMediaFolder: Error retrieving file: %v", err) http.Error(w, "Error retrieving file", http.StatusBadRequest) return } @@ -745,13 +923,13 @@ func handleUploadMediaFolder(w http.ResponseWriter, r *http.Request) { // Generate a unique filename ext := filepath.Ext(header.Filename) filename := fmt.Sprintf("%d%s", time.Now().UnixNano(), ext) - - // Create the full path for the new file fullPath := filepath.Join(config.Server.MediaFolder, filename) + log.Printf("handleUploadMediaFolder: Saving uploaded file as %s", fullPath) // Create a new file in the media folder dst, err := os.Create(fullPath) if err != nil { + log.Printf("handleUploadMediaFolder: Error creating file %s: %v", fullPath, err) http.Error(w, "Error creating file", http.StatusInternalServerError) return } @@ -760,6 +938,7 @@ func handleUploadMediaFolder(w http.ResponseWriter, r *http.Request) { // Copy the uploaded file to the destination _, err = io.Copy(dst, file) if err != nil { + log.Printf("handleUploadMediaFolder: Error saving file %s: %v", fullPath, err) http.Error(w, "Error saving file", http.StatusInternalServerError) return } @@ -771,12 +950,14 @@ func handleUploadMediaFolder(w http.ResponseWriter, r *http.Request) { Filename: filename, } + log.Printf("handleUploadMediaFolder: Successfully uploaded file %s", filename) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(response) } func handleUploadMedia(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { + log.Printf("handleUploadMedia: Method not allowed - %s", r.Method) http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } @@ -784,12 +965,14 @@ func handleUploadMedia(w http.ResponseWriter, r *http.Request) { // Parse the multipart form data with a 32MB limit err := r.ParseMultipartForm(32 << 20) if err != nil { + log.Printf("handleUploadMedia: Error parsing form data: %v", err) http.Error(w, "Error parsing form data", http.StatusBadRequest) return } file, header, err := r.FormFile("file") if err != nil { + log.Printf("handleUploadMedia: Error retrieving file: %v", err) http.Error(w, "Error retrieving file", http.StatusBadRequest) return } @@ -798,13 +981,13 @@ func handleUploadMedia(w http.ResponseWriter, r *http.Request) { // Generate a unique filename ext := filepath.Ext(header.Filename) filename := fmt.Sprintf("%d%s", time.Now().UnixNano(), ext) - - // Create the full path for the new file fullPath := filepath.Join(config.Server.MediaFolder, filename) + log.Printf("handleUploadMedia: Saving uploaded file as %s", fullPath) // Create a new file in the media folder dst, err := os.Create(fullPath) if err != nil { + log.Printf("handleUploadMedia: Error creating file %s: %v", fullPath, err) http.Error(w, "Error creating file", http.StatusInternalServerError) return } @@ -813,6 +996,7 @@ func handleUploadMedia(w http.ResponseWriter, r *http.Request) { // Copy the uploaded file to the destination _, err = io.Copy(dst, file) if err != nil { + log.Printf("handleUploadMedia: Error saving file %s: %v", fullPath, err) http.Error(w, "Error saving file", http.StatusInternalServerError) return } @@ -824,24 +1008,28 @@ func handleUploadMedia(w http.ResponseWriter, r *http.Request) { Filename: filename, } + log.Printf("handleUploadMedia: Successfully uploaded file %s", filename) w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(response) } func handleDeleteMedia(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodDelete { + log.Printf("handleDeleteMedia: Method not allowed - %s", r.Method) http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return } filename := r.URL.Query().Get("file") if filename == "" { + log.Println("handleDeleteMedia: Filename is required") http.Error(w, "Filename is required", http.StatusBadRequest) return } // Ensure the filename is safe if strings.Contains(filename, "..") { + log.Printf("handleDeleteMedia: Invalid filename attempted: %s", filename) http.Error(w, "Invalid filename", http.StatusBadRequest) return } @@ -851,6 +1039,7 @@ func handleDeleteMedia(w http.ResponseWriter, r *http.Request) { // Check if file exists if _, err := os.Stat(fullPath); os.IsNotExist(err) { + log.Printf("handleDeleteMedia: File not found: %s", fullPath) http.Error(w, "File not found", http.StatusNotFound) return } @@ -858,37 +1047,55 @@ func handleDeleteMedia(w http.ResponseWriter, r *http.Request) { // Delete the file err := os.Remove(fullPath) if err != nil { + log.Printf("handleDeleteMedia: Error deleting file %s: %v", fullPath, err) http.Error(w, "Error deleting file", http.StatusInternalServerError) return } + log.Printf("handleDeleteMedia: Successfully deleted file %s", fullPath) // Also delete thumbnail if it exists thumbPath := filepath.Join(config.Server.MediaFolder, "thumb_"+filename) - _ = os.Remove(thumbPath) // Ignore error as thumbnail might not exist + err = os.Remove(thumbPath) + if err != nil { + log.Printf("handleDeleteMedia: Thumbnail not found or error deleting thumbnail %s: %v", thumbPath, err) + } else { + log.Printf("handleDeleteMedia: Successfully deleted thumbnail %s", thumbPath) + } w.WriteHeader(http.StatusOK) json.NewEncoder(w).Encode(map[string]string{"status": "success"}) } func createImageWithImagePig(prompt string, outputFile string) error { + log.Println("createImageWithImagePig: Loading environment variables") // Load environment variables from .env file if err := godotenv.Load(); err != nil { + log.Printf("createImageWithImagePig: Error loading .env file: %v", err) return fmt.Errorf("Error loading .env file: %v", err) } // Get API key from environment apiKey := os.Getenv("IMAGEPIG_API_KEY") if apiKey == "" { + log.Println("createImageWithImagePig: IMAGEPIG_API_KEY not found in environment") return fmt.Errorf("IMAGEPIG_API_KEY not found in environment") } + log.Println("createImageWithImagePig: IMAGEPIG_API_KEY loaded successfully") // Create client client := NewFluxClient(apiKey) + log.Println("createImageWithImagePig: FluxClient created") // Generate landscape image + log.Printf("createImageWithImagePig: Generating landscape image with prompt: %s", prompt) if err := client.GenerateLandscapeImage(prompt, outputFile); err != nil { + log.Printf("createImageWithImagePig: Error generating image: %v", err) return fmt.Errorf("Error generating image: %v", err) } + log.Printf("createImageWithImagePig: Image generated and saved to %s", outputFile) return nil } + +// Helper functions are moved to utils.go +// Types are moved to types.go diff --git a/assets/img/UniverseMathscapePrompt/Bing_Image_Creator.png b/assets/img/UniverseMathscapePrompt/Bing_Image_Creator.png new file mode 100644 index 0000000..80a8cae Binary files /dev/null and b/assets/img/UniverseMathscapePrompt/Bing_Image_Creator.png differ diff --git a/assets/img/UniverseMathscapePrompt/DALL_E.webp b/assets/img/UniverseMathscapePrompt/DALL_E.webp new file mode 100644 index 0000000..2d08616 Binary files /dev/null and b/assets/img/UniverseMathscapePrompt/DALL_E.webp differ diff --git a/assets/img/UniverseMathscapePrompt/GenerateMarkdown.ps1 b/assets/img/UniverseMathscapePrompt/GenerateMarkdown.ps1 new file mode 100644 index 0000000..eeb852e --- /dev/null +++ b/assets/img/UniverseMathscapePrompt/GenerateMarkdown.ps1 @@ -0,0 +1,36 @@ +# Get the script's directory path +$scriptPath = Split-Path -Parent $MyInvocation.MyCommand.Definition +$outputFile = Join-Path $scriptPath "output.md" + +Write-Host "Script directory: $scriptPath" +Write-Host "Output file path: $outputFile" + +# Ensure the output file is empty before starting +Set-Content -Path $outputFile -Value "" + +# Get only image files (including .webp files) +$imageFiles = Get-ChildItem -Path $scriptPath -File | Where-Object { + $_.Extension -match '\.(png|jpg|jpeg|gif|webp|svg)$' +} + +Write-Host "Found $($imageFiles.Count) image files" + +foreach ($file in $imageFiles) { + if ($file.Name -eq "GenerateMarkdown.ps1" -or $file.Name -eq "output.md" -or $file.Name -eq "prompt.md") { + Write-Host "Skipping non-image file: $($file.Name)" + continue + } + + Write-Host "Processing file: $($file.Name)" + + try { + # Append the Markdown entry to the output file + Add-Content -Path $outputFile -Value "- src: ""img/UniverseMathscapePrompt/$($file.Name)""" + Add-Content -Path $outputFile -Value " title: ""$($file.BaseName)""" + Write-Host "Added content for: $($file.Name)" + } catch { + Write-Host "Error processing $($file.Name): $_" + } +} + +Write-Host "Markdown file generated as $outputFile" diff --git a/assets/img/UniverseMathscapePrompt/JanusPro7Bds.webp b/assets/img/UniverseMathscapePrompt/JanusPro7Bds.webp new file mode 100644 index 0000000..b1d914c Binary files /dev/null and b/assets/img/UniverseMathscapePrompt/JanusPro7Bds.webp differ diff --git a/assets/img/UniverseMathscapePrompt/JanusPro7Bds2.webp b/assets/img/UniverseMathscapePrompt/JanusPro7Bds2.webp new file mode 100644 index 0000000..5cc1649 Binary files /dev/null and b/assets/img/UniverseMathscapePrompt/JanusPro7Bds2.webp differ diff --git a/assets/img/UniverseMathscapePrompt/JanusPro7Bds3.webp b/assets/img/UniverseMathscapePrompt/JanusPro7Bds3.webp new file mode 100644 index 0000000..5cc1649 Binary files /dev/null and b/assets/img/UniverseMathscapePrompt/JanusPro7Bds3.webp differ diff --git a/assets/img/UniverseMathscapePrompt/JanusPro7Bds4.webp b/assets/img/UniverseMathscapePrompt/JanusPro7Bds4.webp new file mode 100644 index 0000000..ab4feb4 Binary files /dev/null and b/assets/img/UniverseMathscapePrompt/JanusPro7Bds4.webp differ diff --git a/assets/img/UniverseMathscapePrompt/JanusPro7Bds5.webp b/assets/img/UniverseMathscapePrompt/JanusPro7Bds5.webp new file mode 100644 index 0000000..ecae5f6 Binary files /dev/null and b/assets/img/UniverseMathscapePrompt/JanusPro7Bds5.webp differ diff --git a/assets/img/UniverseMathscapePrompt/PicLumen_Art_V1.webp b/assets/img/UniverseMathscapePrompt/PicLumen_Art_V1.webp new file mode 100644 index 0000000..2f0f33e Binary files /dev/null and b/assets/img/UniverseMathscapePrompt/PicLumen_Art_V1.webp differ diff --git a/assets/img/UniverseMathscapePrompt/PicLumen_Realistic_V2.png b/assets/img/UniverseMathscapePrompt/PicLumen_Realistic_V2.png new file mode 100644 index 0000000..c2a41bd Binary files /dev/null and b/assets/img/UniverseMathscapePrompt/PicLumen_Realistic_V2.png differ diff --git a/assets/img/UniverseMathscapePrompt/Qwen2_5_Plus.png b/assets/img/UniverseMathscapePrompt/Qwen2_5_Plus.png new file mode 100644 index 0000000..3bb4926 Binary files /dev/null and b/assets/img/UniverseMathscapePrompt/Qwen2_5_Plus.png differ diff --git a/assets/img/UniverseMathscapePrompt/claude.svg b/assets/img/UniverseMathscapePrompt/claude.svg new file mode 100644 index 0000000..574d1c0 --- /dev/null +++ b/assets/img/UniverseMathscapePrompt/claude.svg @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Δ + + + ⨀ + + + + + + + + + + + + + + diff --git a/assets/img/UniverseMathscapePrompt/flux1_schnell.png b/assets/img/UniverseMathscapePrompt/flux1_schnell.png new file mode 100644 index 0000000..e7c33f4 Binary files /dev/null and b/assets/img/UniverseMathscapePrompt/flux1_schnell.png differ diff --git a/assets/img/UniverseMathscapePrompt/output.md b/assets/img/UniverseMathscapePrompt/output.md new file mode 100644 index 0000000..2916995 --- /dev/null +++ b/assets/img/UniverseMathscapePrompt/output.md @@ -0,0 +1,26 @@ + +- src: "img/UniverseMathscapePrompt/Bing Image Creator.png" + title: "Bing Image Creator" + params: + description: "Create with the prompt." +- src: "img/UniverseMathscapePrompt/claude.svg" + title: "claude" + +- src: "img/UniverseMathscapePrompt/DALL_E.webp" + title: "DALL_E" +- src: "img/UniverseMathscapePrompt/flux1_schnell.png" + title: "flux1_schnell" +- src: "img/UniverseMathscapePrompt/JanusPro7Bds.webp" + title: "JanusPro7Bds" +- src: "img/UniverseMathscapePrompt/JanusPro7Bds2.webp" + title: "JanusPro7Bds2" +- src: "img/UniverseMathscapePrompt/JanusPro7Bds3.webp" + title: "JanusPro7Bds3" +- src: "img/UniverseMathscapePrompt/JanusPro7Bds4.webp" + title: "JanusPro7Bds4" +- src: "img/UniverseMathscapePrompt/JanusPro7Bds5.webp" + title: "JanusPro7Bds5" +- src: "img/UniverseMathscapePrompt/PicLumen Art V1.webp" + title: "PicLumen Art V1" +- src: "img/UniverseMathscapePrompt/PicLumen Realistic V2.png" + title: "PicLumen Realistic V2" diff --git a/assets/img/UniverseMathscapePrompt/prompt.md b/assets/img/UniverseMathscapePrompt/prompt.md new file mode 100644 index 0000000..f5a5815 --- /dev/null +++ b/assets/img/UniverseMathscapePrompt/prompt.md @@ -0,0 +1,30 @@ +**Optimized Image Creation Prompt:** +"Visualize a surreal, hyper-detained universe where symbolic mathematics defines physical laws. Design an ethereal landscape using these guidelines: + +1. **Core Visual Metaphors**: +- *Fractal Time*: Depict time as interlocking geometric lattices (e.g., recursive tetrahedrons or Penrose tiling) where past/present/future coexist. +- *Topological Gravity*: Show gravity as warped, glowing manifolds (think Klein bottle-like distortions) pulling celestial bodies into Möbius strip orbits. + +2. **Symbolic Architecture**: +- Render primal symbols (e.g., **Δ**, **⨀**) as *glowing hieroglyphs* etched into floating monoliths or encoded in particle trails. +- Use *hyperdimensional geometry*: Merge 4D Calabi-Yau shapes with adversarial neural network patterns (modular, tessellated grids). + +3. **Material Palette**: +- *Matter*: Translucent, iridescent structures with embedded equations (e.g., shimmering LaTeX symbols in crystal). +- *Energy*: Fluid light in non-Euclidian rivers (CMYK gradients for unknown forces). + +4. **Dynamic Anomalies**: +- Illustrate *paradox stabilization*: Black holes as self-solving Rube Goldberg machines with gears of logic gates. +- Show *symbolic torsion*: Regions where Pi (π) visibly fractures, bending spiral galaxies into Fibonacci-violating arcs. + +5. **Style & Mood**: +- Blend *Renaissance cartography* with *glitch-core textures*. +- Atmosphere: Cosmic dusk with ultra-chromatic shadows (impossible colors like hyperbolic orange or quantum blue). + +--- +**Key Commands for AI Art Models**: +- Use terms like *"mathematically alien," "symbolic surrealism," "non-Newtonian lighting," "topological horror vacui,"* and *"ultra-detail 16K"*. +- Avoid generic sci-fi: No planets, spaceships, or humanoids. Prioritize *abstraction* over literal astrophysics." + +--- +This prompt steers image generators toward *conceptual novelty* by replacing stars/planets with hypermathematical constructs, while retaining enough structure to avoid chaos. Adjust symbols or geometry to target specific aesthetics (e.g., Aztec-divergence vs. quantum-punk). \ No newline at end of file diff --git a/content/en/blog/2025-01-28-gallery-my-text-to-image-generation-test-prompt-alternative-universe.md b/content/en/blog/2025-01-28-gallery-my-text-to-image-generation-test-prompt-alternative-universe.md new file mode 100644 index 0000000..f82a900 --- /dev/null +++ b/content/en/blog/2025-01-28-gallery-my-text-to-image-generation-test-prompt-alternative-universe.md @@ -0,0 +1,50 @@ +--- +title: "Text-to-image generation test prompt: Alternative universe" +description: | + Image gallery for Text-to-Image generation enhanced prompt for generation an image for an alternative universe +date: 2025-01-27T11:08:26.847Z +draft: false +tags: + - AI Art + - Text-to-Image +categories: + - Artificial Intelligence +thumbnail: + url: img/UniverseMathscapePrompt/JanusPro7Bds4.webp + author: Janus Pro 7B - created by d.o.it on HF +lang: en +modules: + - slideshow-gallery +resources: + - src: img/UniverseMathscapePrompt/Bing_Image_Creator.png + title: Bing Image Creator + - src: img/UniverseMathscapePrompt/DALL_E.webp + title: DALL_E + - src: img/UniverseMathscapePrompt/flux1_schnell.png + title: flux.1.schnell + - src: img/UniverseMathscapePrompt/JanusPro7Bds.webp + title: JanusPro7B huggingface + - src: img/UniverseMathscapePrompt/JanusPro7Bds2.webp + title: JanusPro7B huggingface + - src: img/UniverseMathscapePrompt/JanusPro7Bds3.webp + title: JanusPro7B huggingface + - src: img/UniverseMathscapePrompt/JanusPro7Bds4.webp + title: JanusPro7B huggingface + - src: img/UniverseMathscapePrompt/JanusPro7Bds5.webp + title: JanusPro7B huggingface + - src: img/UniverseMathscapePrompt/PicLumen_Art_V1.webp + title: PicLumen Art V1 + - src: img/UniverseMathscapePrompt/PicLumen_Realistic_V2.png + title: PicLumen Realistic V2 + - src: img/UniverseMathscapePrompt/Qwen2_5_Plus.png + title: Qwen2.5 Plus +slug: text-image-generation-test-prompt-alternative-universe +--- + +## My Text-Image Generation for different models + +{{< file show="false" full="false" path="./assets/img/UniverseMathscapePrompt/prompt.md" id="file-collapse-4" >}} + +## Gallery + +{{< slideshow-gallery >}} diff --git a/hugo_stats.json b/hugo_stats.json index abf819d..3ee3605 100644 --- a/hugo_stats.json +++ b/hugo_stats.json @@ -7,12 +7,17 @@ "br", "button", "code", + "defs", "div", "em", + "fedisplacementmap", + "feturbulence", "figcaption", "figure", + "filter", "footer", "form", + "g", "h1", "h2", "h3", @@ -26,6 +31,8 @@ "input", "label", "li", + "line", + "lineargradient", "link", "mark", "meta", @@ -35,9 +42,11 @@ "p", "path", "pre", + "rect", "script", "small", "span", + "stop", "strong", "sup", "svg", @@ -45,6 +54,7 @@ "table", "tbody", "td", + "text", "th", "thead", "time", @@ -54,6 +64,7 @@ "use" ], "classes": [ + "%!s()", "active", "align-items-center", "align-items-end", @@ -295,6 +306,7 @@ "multi-file-basket-json", "multi-file-collapse-1", "multi-file-collapse-2", + "multi-file-collapse-4", "multi-file-collapse-footer-1", "multi-file-collapse-py-script", "multi-generatePlaywrightTest-py", @@ -489,6 +501,7 @@ "body-file-basket-json", "body-file-collapse-1", "body-file-collapse-2", + "body-file-collapse-4", "body-file-collapse-footer-1", "body-file-collapse-py-script", "body-generatePlaywrightTest-py", @@ -578,15 +591,18 @@ "footer-file-basket-json", "footer-file-collapse-1", "footer-file-collapse-2", + "footer-file-collapse-4", "footer-file-collapse-footer-1", "footer-file-collapse-py-script", "footer-generatePlaywrightTest-py", "footer-playwright-config-js", "footer-showCustom404-spec-js", "footer-update_free_basket_calendar", + "fractalGradient", "free-basket-streams-table", "frontend", "functions", + "gallery", "generate-a-starting-point-for-all-websites-pages", "generated-playwright-js-file", "generating-a-license-report-for-nuget-packages-in-your-net-core-solution", @@ -594,6 +610,7 @@ "github-action", "github-readme", "github-repository", + "glitchFilter", "google-calendar", "grafik", "hinode-hugo-lightbox-gallery-integration", @@ -621,6 +638,7 @@ "listView", "liveToastSaveThemMode", "lokale-installation", + "my-text-image-generation-for-different-models", "navbar-0-collapse", "net-create-excel-or-text-license-file-for-used-nuget-packages", "nuget-package-license", diff --git a/output.md b/output.md new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/output.md @@ -0,0 +1 @@ +