all repos — mdget @ 509eee2768c7a02a0c6c106e93313d46dc846f67

Unnamed repository; edit this file 'description' to name the repository.

cmd/mdget.go (view raw)

  1package main
  2
  3import (
  4	"fmt"
  5	"os"
  6	"strings"
  7	"time"
  8
  9	htmltomarkdown "github.com/JohannesKaufmann/html-to-markdown/v2"
 10	"github.com/JohannesKaufmann/html-to-markdown/v2/converter"
 11	"github.com/alexflint/go-arg"
 12	"github.com/imroc/req/v3"
 13)
 14
 15var (
 16	version   string
 17	buildDate string
 18)
 19
 20// Args defines the command-line arguments for mdget
 21type Args struct {
 22	URL       string `arg:"positional" help:"URL to fetch and convert to markdown"`
 23	Output    string `arg:"-o,--output" help:"Output file (default: stdout)" default:""`
 24	Timeout   int    `arg:"-t,--timeout" help:"Request timeout in seconds" default:"30"`
 25	UserAgent string `arg:"-u,--user-agent" help:"Custom User-Agent header" default:"mdget/0.1.0"`
 26}
 27
 28// Version implements the Versioned interface for go-arg
 29func (Args) Version() string {
 30	return fmt.Sprintf("mdget v%s (built %s)", version, buildDate)
 31}
 32
 33// Description returns the program description for help text
 34func (Args) Description() string {
 35	return "Fetch a URL and convert its HTML content to Markdown."
 36}
 37
 38// Epilogue returns the help text epilogue
 39func (Args) Epilogue() string {
 40	return `Examples:
 41  mdget https://example.com
 42  mdget --output page.md https://example.com
 43  mdget --timeout 10 --user-agent "MyBot/1.0" example.com`
 44}
 45
 46func main() {
 47	// Parse command-line arguments
 48	var args Args
 49
 50	// Use MustParse which handles --help and --version automatically
 51	parser := arg.MustParse(&args)
 52
 53	// Check if URL is provided (help/version flags are already handled by MustParse)
 54	if args.URL == "" {
 55		fmt.Fprintf(os.Stderr, "Error: URL is required\n\n")
 56		parser.WriteUsage(os.Stderr)
 57		os.Exit(1)
 58	}
 59
 60	// Validate URL starts with http:// or https://
 61	url := args.URL
 62	if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") {
 63		url = "https://" + url
 64	}
 65
 66	// Determine output destination
 67	var output *os.File = os.Stdout
 68	if args.Output != "" {
 69		f, err := os.Create(args.Output)
 70		if err != nil {
 71			fmt.Fprintf(os.Stderr, "Error creating output file: %v\n", err)
 72			os.Exit(1)
 73		}
 74		defer f.Close()
 75		output = f
 76	}
 77
 78	// Fetch the URL using req with timeout and custom User-Agent
 79	client := req.C().
 80		SetTimeout(time.Duration(args.Timeout) * time.Second).
 81		SetUserAgent(args.UserAgent)
 82
 83	resp, err := client.R().Get(url)
 84	if err != nil {
 85		fmt.Fprintf(os.Stderr, "Error fetching URL: %v\n", err)
 86		os.Exit(1)
 87	}
 88
 89	if !resp.IsSuccessState() {
 90		fmt.Fprintf(os.Stderr, "HTTP error: %s\n", resp.Status)
 91		os.Exit(1)
 92	}
 93
 94	// Get HTML content
 95	html := resp.String()
 96
 97	// Convert HTML to Markdown with domain context for relative URLs
 98	markdown, err := htmltomarkdown.ConvertString(
 99		html,
100		converter.WithDomain(url),
101	)
102	if err != nil {
103		fmt.Fprintf(os.Stderr, "Error converting HTML to Markdown: %v\n", err)
104		os.Exit(1)
105	}
106
107	// Output Markdown to destination
108	fmt.Fprint(output, markdown)
109}