package main import ( "bufio" "flag" "fmt" "io" "io/fs" "log" "os" "path/filepath" "regexp" "strings" ) type Attachment struct { Filename string Note string } type matches chan Attachment func scanReader(r io.Reader, path string, matchChan matches) { log.Printf("scanning markdown file: %s", path) pat := regexp.MustCompile(`\[\[(Resources\/attachments\/.*?)\]\]`) s := bufio.NewScanner(r) for s.Scan() { tok := s.Text() matches := pat.FindAllStringSubmatch(tok, -1) if len(matches) > 0 { log.Printf("media found in %s: %#+v\n", path, matches) for _, match := range matches { dirs := strings.Split(path, "/") noteFilename := dirs[len(dirs)-2] matchChan <- Attachment{Filename: match[1], Note: noteFilename} } } } } func walkFunc(matchChan matches) filepath.WalkFunc { return func(path string, info fs.FileInfo, err error) error { if err != nil { return nil } if info.IsDir() { return nil } f, err := os.Open(path) if err != nil { return err } if strings.HasSuffix(path, "index.md") { scanReader(f, path, matchChan) } return nil } } func moveAttachment(att Attachment, dest string) error { destPath := filepath.Join(dest, strings.Split(att.Note, ".")[0]) log.Println("moving files:", destPath) _, err := copy(att.Filename, filepath.Join(destPath, filepath.Base(att.Filename))) return err } func copy(src, dst string) (int64, error) { sourceFileStat, err := os.Stat(src) if err != nil { return 0, err } if !sourceFileStat.Mode().IsRegular() { return 0, fmt.Errorf("%s is not a regular file", src) } source, err := os.Open(src) if err != nil { return 0, err } defer source.Close() destination, err := os.Create(dst) if err != nil { return 0, err } defer destination.Close() nBytes, err := io.Copy(destination, source) return nBytes, err } func main() { var ( origin string destination string ) flag.StringVar(&origin, "origin", "./content/", "directory containing Obsidian Markdown posts") flag.StringVar(&destination, "destination", "/tmp/blog/content/posts/", "destination for posts and their attachments") flag.Parse() attachments := make(matches) // for i := 0; i < 5; i++ { go func() { for match := range attachments { err := moveAttachment(match, destination) if err != nil { log.Fatalf("error moving attachment: %s\n", err) } } }() // } err := filepath.Walk(origin, walkFunc(attachments)) if err != nil { log.Fatalf("error walking %s", err) } }