package gempub import ( "bufio" "errors" "fmt" "io" "strings" "time" ) type Metadata struct { Title string // mandatory title of the work GpubVersion string // mandatory Gempub format version: 1.0.0 Index string // path to index.gmi, if none is specified it should be assumed to be in the root Author string // author of the work Language string // BCP 47 language code Charset string // if not set, assume UTF-8 Description string // human-readable description Published time.Time // YYYY when date is unknown PublishDate time.Time // YYYY-MM-DD eg. 2006-01-02 RevisionDate time.Time // YYYY-MM-DD eg. 2006-01-02 Copyright string // copyright of the book License string // license of the book Version string // human readable only, not meant to be parsed Cover string // a JPG or PNG image which can be anywhere in the directory structure } func (m Metadata) Write(w io.Writer) error { if err := m.Valid(); err != nil { return err } if _, err := fmt.Fprintln(w, "title: ", m.Title); err != nil { return err } if _, err := fmt.Fprintln(w, "gpubVersion: ", m.GpubVersion); err != nil { return err } if m.Index != "" { if _, err := fmt.Fprintln(w, "index: ", m.Index); err != nil { return err } } if m.Author != "" { if _, err := fmt.Fprintln(w, "author: ", m.Author); err != nil { return err } } if m.Language != "" { if _, err := fmt.Fprintln(w, "language: ", m.Language); err != nil { return err } } if m.Charset != "" { if _, err := fmt.Fprintln(w, "charset: ", m.Charset); err != nil { return err } } if m.Description != "" { if _, err := fmt.Fprintln(w, "description: ", m.Description); err != nil { return err } } if m.Copyright != "" { if _, err := fmt.Fprintln(w, "copyright: ", m.Copyright); err != nil { return err } } if m.Version != "" { if _, err := fmt.Fprintln(w, "version: ", m.Version); err != nil { return err } } if m.Cover != "" { if _, err := fmt.Fprintln(w, "cover: ", m.Cover); err != nil { return err } } if !m.Published.IsZero() { if _, err := fmt.Fprintln(w, "published: ", m.Published.Format("2006-01-02")); err != nil { return err } } if !m.PublishDate.IsZero() { if _, err := fmt.Fprintln(w, "publishDate: ", m.PublishDate.Format("2006-01-02")); err != nil { return err } } if !m.RevisionDate.IsZero() { if _, err := fmt.Fprintln(w, "revisionDate: ", m.RevisionDate.Format("2006-01-02")); err != nil { return err } } return nil } var ( ErrNoTitle = errors.New("gempub: no title in document") ) func loadDateOrYear(when string) (t time.Time, err error) { if len(when) == 4 { t, err = time.Parse("2006", when) return } t, err = time.Parse("2006-01-02", when) return } func (m Metadata) Valid() error { switch { case m.Title == "": return ErrNoTitle case m.GpubVersion != "1.0.0": return fmt.Errorf("gempub: wrong gempub version: %v", m.GpubVersion) } return nil } func ReadMetadata(r io.Reader) (*Metadata, error) { var result Metadata sc := bufio.NewScanner(r) for sc.Scan() { line := sc.Text() sp := strings.SplitN(line, ":", 2) key, val := sp[0], sp[1] val = strings.TrimSpace(val) switch key { case "title": result.Title = val case "gpubVersion": result.GpubVersion = val case "index": result.Index = val case "author": result.Author = val case "language": result.Language = val case "charset": result.Charset = val case "description": result.Description = val case "published": when, err := loadDateOrYear(val) if err != nil { return nil, fmt.Errorf("gempub: can't understand date %q: %v", val, err) } result.Published = when case "publishDate": when, err := loadDateOrYear(val) if err != nil { return nil, fmt.Errorf("gempub: can't understand date %q: %v", val, err) } result.PublishDate = when case "revisionDate": when, err := loadDateOrYear(val) if err != nil { return nil, fmt.Errorf("gempub: can't understand date %q: %v", val, err) } result.RevisionDate = when case "copyright": result.Copyright = val case "license": result.License = val case "cover": result.Cover = val } } return &result, result.Valid() }