opf.go 2.63 KB
Newer Older
ale's avatar
ale committed
1 2 3 4
package liber

import (
	"encoding/xml"
5
	"errors"
ale's avatar
ale committed
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
	"io"
	"os"
	"path/filepath"
	"strings"
)

type opfIdentifier struct {
	Scheme string `xml:"http://www.idpf.org/2007/opf scheme,attr"`
	Value  string `xml:",chardata"`
}

type opfMeta struct {
	XMLName     xml.Name        `xml:"http://www.idpf.org/2007/opf metadata"`
	Title       string          `xml:"http://purl.org/dc/elements/1.1/ title"`
	Date        string          `xml:"http://purl.org/dc/elements/1.1/ date"`
	Description string          `xml:"http://purl.org/dc/elements/1.1/ description"`
	Creator     []string        `xml:"http://purl.org/dc/elements/1.1/ creator"`
	Language    []string        `xml:"http://purl.org/dc/elements/1.1/ language"`
	Publisher   []string        `xml:"http://purl.org/dc/elements/1.1/ publisher"`
	Identifier  []opfIdentifier `xml:"http://purl.org/dc/elements/1.1/ identifier"`
}

type opfPackage struct {
	Meta *opfMeta
}

func (o *opfMeta) ToMetadata() *Metadata {
	m := &Metadata{
		Title:       o.Title,
		Description: o.Description,
		Publisher:   o.Publisher,
		Language:    o.Language,
	}
	if o.Date != "" && o.Date != "0101-01-01T00:00:00+00:00" {
		m.Date = toYear(o.Date)
	}
	for _, c := range o.Creator {
		for _, cc := range strings.Split(c, ",") {
			m.Creator = append(m.Creator, strings.TrimSpace(cc))
		}
	}
	var uuid string
	for _, id := range o.Identifier {
		if id.Scheme == "ISBN" {
			m.ISBN = append(m.ISBN, id.Value)
		} else if id.Scheme == "uuid" {
			uuid = id.Value
		}
	}
	m.Sources = []MetadataSource{{
		Name: "opf",
		ID:   uuid,
	}}
	return m
}

func opfParse(r io.Reader) (*Metadata, error) {
	var opf opfPackage
	if err := xml.NewDecoder(r).Decode(&opf); err != nil {
		return nil, err
	}
	return opf.Meta.ToMetadata(), nil
}

func opfOpen(path string) (*Metadata, error) {
	file, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer file.Close()
	return opfParse(file)
}

79 80
func replaceExt(path, ext string) string {
	return strings.TrimSuffix(path, filepath.Ext(path)) + ext
ale's avatar
ale committed
81
}
82 83 84 85

type opfProvider struct{}

func (p *opfProvider) Lookup(storage *FileStorage, path, filetype string) (*Metadata, error) {
86 87 88
	paths := []string{
		filepath.Join(filepath.Dir(path), "metadata.opf"),
		replaceExt(path, ".opf"),
89
	}
90 91 92 93
	for _, opfpath := range paths {
		if m, err := opfOpen(storage.Abs(opfpath)); err == nil {
			return m, err
		}
94
	}
95
	return nil, errors.New("no OPF metadata found")
96 97 98
}

func (p *opfProvider) GetBookCover(storage *FileStorage, path string) (string, error) {
99
	coverPath := filepath.Join(filepath.Dir(path), "cover.jpg")
100 101 102 103 104 105 106 107 108
	if storage.Exists(coverPath) {
		return coverPath, nil
	}
	return "", nil
}

func (p *opfProvider) Name() string {
	return "opf"
}