package tal import ( "bufio" "errors" "fmt" "io/ioutil" "os" "path" "path/filepath" "regexp" "strings" ) var metaRegex = regexp.MustCompile(`^#([a-zA-Z]+) (.*)$`) type Repo struct { URL string Path string Update bool Books []Book } func (lr *Repo) GetMeta() map[string]map[string][]Book { meta := map[string]map[string][]Book{} for _, book := range lr.Books { if book.Meta["DELETED"] != "" { continue } for key, value := range book.Meta { if meta[key] == nil { meta[key] = map[string][]Book{} } meta[key][value] = append(meta[key][value], book) } } return meta } func (lr *Repo) Scan() error { books := lr.scanTree(lr.Path, 1, 3, ".muse") if len(books) == 0 { return errors.New(fmt.Sprintf("No library found at %s", lr.Path)) } for _, p := range books { meta, err := readMeta(p) if err != nil { continue } lr.Books = append(lr.Books, Book{ Path: p, Base: strings.TrimSuffix(path.Base(p), ".muse"), Meta: meta, }) } return nil } func (lr *Repo) scanTree(p string, dirlen uint8, max uint8, suffix string) []string { var paths []string files, err := ioutil.ReadDir(p) if err != nil { return paths } for _, entry := range files { name := entry.Name() subdir := filepath.Join(p, name) if dirlen == max { if strings.HasSuffix(name, suffix) { paths = append(paths, subdir) } } else { if !entry.IsDir() || len(name) != int(dirlen) { continue } paths = append(paths, lr.scanTree(subdir, dirlen+1, max, suffix)...) } } return paths } func readMeta(p string) (map[string]string, error) { meta := map[string]string{} f, err := os.Open(p) if err != nil { return nil, err } scanner := bufio.NewScanner(f) for scanner.Scan() { line := scanner.Text() if len(line) > 0 && line[0] == '#' { result := metaRegex.FindStringSubmatch(line) if len(result) > 0 { tag := strings.TrimSpace(result[1]) value := strings.TrimSpace(result[2]) meta[tag] = value } } else { break } } f.Close() return meta, nil }