// readEPUBSeriesInfo reads the series metadata from an epub book.
readEPUBSeriesInfo reads the series metadata from an epub book.
// readEPUBSeriesInfo reads the series metadata from an epub book .
func readEPUBSeriesInfo(filename string) (series string, index float64, err error) {
	zr, err := zip.OpenReader(filename)
	if err != nil {
		return "", 0, fmt.Errorf("could not open ebook: %w", err)
	}
	defer zr.Close()
	var rootfile string
	for _, f := range zr.File {
		if strings.TrimLeft(strings.ToLower(f.Name), "/") == "meta-inf/container.xml" {
			rc, err := f.Open()
			if err != nil {
				return "", 0, fmt.Errorf("could not open container.xml: %w", err)
			}
			doc := etree.NewDocument()
			_, err = doc.ReadFrom(rc)
			if err != nil {
				rc.Close()
				return "", 0, fmt.Errorf("could not parse container.xml: %w", err)
			}
			if el := doc.FindElement("//rootfiles/rootfile[@full-path]"); el != nil {
				rootfile = el.SelectAttrValue("full-path", "")
			}
			rc.Close()
			break
		}
	}
	if rootfile == "" {
		return "", 0, errors.New("could not open ebook: could not find package document")
	}
	for _, f := range zr.File {
		if strings.TrimLeft(strings.ToLower(f.Name), "/") == strings.TrimLeft(strings.ToLower(rootfile), "/") {
			rc, err := f.Open()
			if err != nil {
				return "", 0, fmt.Errorf("could not open container.xml: %w", err)
			}
			doc := etree.NewDocument()
			_, err = doc.ReadFrom(rc)
			if err != nil {
				rc.Close()
				return "", 0, fmt.Errorf("could not parse container.xml: %w", err)
			}
			if el := doc.FindElement("//meta[@name='calibre:series']"); el != nil {
				series = el.SelectAttrValue("content", "")
				if el := doc.FindElement("//meta[@name='calibre:series_index']"); el != nil {
					index, _ = strconv.ParseFloat(el.SelectAttrValue("content", "0"), 64)
				}
			}
			if series == "" {
				if el := doc.FindElement("//meta[@property='belongs-to-collection']"); el != nil {
					series = strings.TrimSpace(el.Text())
					var ctype string
					if id := el.SelectAttrValue("id", ""); id != "" {
						for _, el := range doc.FindElements("//meta[@refines='#" + id + "']") {
							val := strings.TrimSpace(el.Text())
							switch el.SelectAttrValue("property", "") {
							case "collection-type":
								ctype = val
							case "group-position":
								index, _ = strconv.ParseFloat(val, 64)
							}
						}
					}
					if ctype != "" && ctype != "series" {
						series, index = "", 0
					}
				}
			}
			break
		}
	}
	return series, index, nil
}
func readEPUBSeriesInfo ( filename string ) ( series string , index float64 , err error ) { zr , err := zip . OpenReader ( filename ) if err != nil { return " " , 0 , fmt . Errorf ( " " , err ) } defer zr . Close ( ) var rootfile string for _ , f := range zr . File { if strings . TrimLeft ( strings . ToLower ( f . Name ) , " " ) == " " { rc , err := f . Open ( ) if err != nil { return " " , 0 , fmt . Errorf ( " " , err ) } doc := etree . NewDocument ( ) _ , err = doc . ReadFrom ( rc ) if err != nil { rc . Close ( ) return " " , 0 , fmt . Errorf ( " " , err ) } if el := doc . FindElement ( " " ) ; el != nil { rootfile = el . SelectAttrValue ( " " , " " ) } rc . Close ( ) break } } if rootfile == " " { return " " , 0 , errors . New ( " " ) } for _ , f := range zr . File { if strings . TrimLeft ( strings . ToLower ( f . Name ) , " " ) == strings . TrimLeft ( strings . ToLower ( rootfile ) , " " ) { rc , err := f . Open ( ) if err != nil { return " " , 0 , fmt . Errorf ( " " , err ) } doc := etree . NewDocument ( ) _ , err = doc . ReadFrom ( rc ) if err != nil { rc . Close ( ) return " " , 0 , fmt . Errorf ( " " , err ) } if el := doc . FindElement ( " " ) ; el != nil { series = el . SelectAttrValue ( " " , " " ) if el := doc . FindElement ( " " ) ; el != nil { index , _ = strconv . ParseFloat ( el . SelectAttrValue ( " " , " " ) , 64 ) } } if series == " " { if el := doc . FindElement ( " " ) ; el != nil { series = strings . TrimSpace ( el . Text ( ) ) var ctype string if id := el . SelectAttrValue ( " " , " " ) ; id != " " { for _ , el := range doc . FindElements ( " " + id + " " ) { val := strings . TrimSpace ( el . Text ( ) ) switch el . SelectAttrValue ( " " , " " ) { case " " : ctype = val case " " : index , _ = strconv . ParseFloat ( val , 64 ) } } } if ctype != " " && ctype != " " { series , index = " " , 0 } } } break } } return series , index , nil }
readEPUBSeriesInfo reads the series metadata from an epub book.
readEPUBSeriesInfo reads the series metadata from an epub book .
// Calibre series metadata // EPUB3 series metadata