Diffstat (limited to 'main.go')
| -rw-r--r-- | main.go | 112 |
1 files changed, 112 insertions, 0 deletions
@@ -0,0 +1,112 @@ +package main + +import ( + "flag" + "io/fs" + "log/slog" + "os" + "path/filepath" + "strings" + "sync" + + "github.com/SayaAndy/saya-today-article-metadata-add/config" + "github.com/SayaAndy/saya-today-article-metadata-add/internal/draft" + "github.com/SayaAndy/saya-today-article-metadata-add/internal/transcoder" +) + +var configPath = flag.String("c", "config.json", "Path to the configuration file") + +func main() { + flag.Parse() + + cfg, err := config.InitConfig(*configPath) + if err != nil { + slog.Error("fail to load configuration", slog.String("error", err.Error())) + os.Exit(1) + } + + slog.SetLogLoggerLevel(cfg.LogLevel) + slog.Info("starting metadata extractor...") + + transcoders := make([]transcoder.Transcoder, 0, len(cfg.Transcoders)) + for _, tcCfg := range cfg.Transcoders { + newTranscoder, ok := transcoder.NewTranscoderMap[tcCfg.Type] + if !ok { + slog.Error("unsupported transcoder type", slog.String("type", tcCfg.Type)) + os.Exit(1) + } + t, err := newTranscoder(tcCfg.Config) + if err != nil { + slog.Error("fail to initialize transcoder", slog.String("type", tcCfg.Type), slog.String("error", err.Error())) + os.Exit(1) + } + transcoders = append(transcoders, t) + slog.Info("initialized transcoder", slog.String("type", tcCfg.Type)) + } + + var drafts []string + err = filepath.WalkDir(cfg.DraftDir, func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + if d.IsDir() { + return nil + } + if strings.HasSuffix(path, cfg.DraftSuffix) { + drafts = append(drafts, path) + } + return nil + }) + if err != nil { + slog.Error("fail to scan draft directory", slog.String("dir", cfg.DraftDir), slog.String("error", err.Error())) + os.Exit(1) + } + slog.Info("scanned drafts", slog.Int("draft_count", len(drafts))) + + semaphore := make(chan struct{}, cfg.MaxConcurrentJobs) + var wg sync.WaitGroup + wg.Add(len(drafts)) + + for _, draftPath := range drafts { + semaphore <- struct{}{} + go func(path string) { + defer wg.Done() + defer func() { <-semaphore }() + + codename := strings.TrimSuffix(filepath.Base(path), cfg.DraftSuffix) + fileLogger := slog.With(slog.String("draft", path), slog.String("codename", codename)) + + content, err := os.ReadFile(path) + if err != nil { + fileLogger.Warn("fail to read draft", slog.String("error", err.Error())) + return + } + + doc, err := draft.ParseDraft(path, codename, content) + if err != nil { + fileLogger.Warn("fail to parse draft", slog.String("error", err.Error())) + return + } + if doc.Metadata == nil { + fileLogger.Info("skip draft without frontmatter metadata") + return + } + + for _, t := range transcoders { + if err := t.Transcode(doc); err != nil { + fileLogger.Warn("transcoder failed", slog.String("transcoder", t.Name()), slog.String("error", err.Error())) + } + } + }(draftPath) + } + + wg.Wait() + + for _, t := range transcoders { + if err := t.Finalize(); err != nil { + slog.Error("fail to finalize transcoder", slog.String("transcoder", t.Name()), slog.String("error", err.Error())) + os.Exit(1) + } + slog.Info("finalized transcoder", slog.String("transcoder", t.Name())) + } +} |