bookends

commit 029ee8df9012b9fdcf7f9d72be88d01d85b97418

Author: Honza Pokorny <honza@redhat.com>

Parse org files instead of yaml

 cmd/build.go | 7 +
 go.mod | 8 +
 go.sum | 22 +++
 pkg/bookends/bookends.go | 247 +++++++++++++++++++++++++++++++++++++++--


diff --git a/cmd/build.go b/cmd/build.go
index da1a208d1e2c0d8a4bdff5d78685ce72671c356f..1551cc9953d3400e8fac0f18190707f6b9d72ff5 100644
--- a/cmd/build.go
+++ b/cmd/build.go
@@ -17,6 +17,8 @@
 package cmd
 
 import (
+	"fmt"
+
 	"git.pokorny.ca/bookends/pkg/bookends"
 	"github.com/spf13/cobra"
 )
@@ -28,6 +30,9 @@ var buildCmd = &cobra.Command{
 	Use:   "build",
 	Short: "",
 	Run: func(cmd *cobra.Command, args []string) {
-		bookends.Build()
+		err := bookends.Build()
+		if err != nil {
+			fmt.Println(err)
+		}
 	},
 }




diff --git a/go.mod b/go.mod
index 558c350f4960ec21ac2c00fd219bd2587f0b078f..04c6725ccdf946ea63a979f7578b42b9bf887157 100644
--- a/go.mod
+++ b/go.mod
@@ -1,5 +1,9 @@
 module git.pokorny.ca/bookends
 
-go 1.15
+go 1.16
 
-require github.com/spf13/cobra v1.1.3
+require (
+	github.com/niklasfasching/go-org v1.5.0 // indirect
+	github.com/spf13/cobra v1.1.3
+	gopkg.in/yaml.v2 v2.4.0
+)




diff --git a/go.sum b/go.sum
index 381fa9ab7818b24b983bad17ba90c79c71829373..9577210ba58e16ffffda440c67d53d39f58c73ce 100644
--- a/go.sum
+++ b/go.sum
@@ -14,6 +14,11 @@ dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
+github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI=
+github.com/alecthomas/chroma v0.8.2/go.mod h1:sko8vR34/90zvl5QdcUdvzL3J8NKjAUx9va9jPuFNoM=
+github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0=
+github.com/alecthomas/kong v0.2.4/go.mod h1:kQOmtJgV+Lb4aj+I2LEn40cbtawdWJ9Y8QLq+lElKxE=
+github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ=
 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
@@ -31,10 +36,12 @@ github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
 github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
 github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
 github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
 github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
+github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
@@ -103,7 +110,9 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
 github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
 github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
 github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
 github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
@@ -117,11 +126,14 @@ github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/niklasfasching/go-org v1.5.0 h1:V8IwoSPm/d61bceyWFxxnQLtlvNT+CjiYIhtZLdnMF0=
+github.com/niklasfasching/go-org v1.5.0/go.mod h1:sSb8ylwnAG+h8MGFDB3R1D5bxf8wA08REfhjShg3kjA=
 github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
 github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
 github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
@@ -138,6 +150,7 @@ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
 github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
+github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
 github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
 github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
 github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
@@ -203,6 +216,8 @@ golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw=
+golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -224,9 +239,15 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200413165638-669c56c373c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -277,6 +298,7 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
 gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
 gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
 gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
 honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=




diff --git a/pkg/bookends/bookends.go b/pkg/bookends/bookends.go
index 7e71fab3daca0417b7b4ad6d23ab958a339f2eef..357a2eb437560c33317e8b2971677c1bd9a4146f 100644
--- a/pkg/bookends/bookends.go
+++ b/pkg/bookends/bookends.go
@@ -1,31 +1,250 @@
 package bookends
 
 import (
+	"bytes"
 	"fmt"
+	"html/template"
+	"io"
+	"net/url"
+	"os"
+	"path"
+	"sort"
+	"strconv"
+	"strings"
 	"time"
+
+	"github.com/niklasfasching/go-org/org"
 )
 
-type DateRead time.Time
+type DateRead struct {
+	time.Time
+}
+
+type Book struct {
+	Author   string        `yaml:"author"`
+	Title    string        `yaml:"title"`
+	ISBN     string        `yaml:"isbn"`
+	DateRead DateRead      `yaml:"date_read"`
+	Rating   int           `yaml:"rating"`
+	Review   template.HTML `yaml:"review"`
+	Tags     []string      `yaml:"tags"`
+}
 
-func (t *DateRead) UnmarshalYAML(unmarshal func(interface{}) error) error {
-	var tm string
-	if err := unmarshal(&tm); err != nil {
+type BooksByDateRead []Book
+
+func (r BooksByDateRead) Len() int      { return len(r) }
+func (r BooksByDateRead) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
+func (r BooksByDateRead) Less(i, j int) bool {
+	return r[i].DateRead.Time.After(r[j].DateRead.Time)
+}
+
+func PathExists(path string) bool {
+	_, err := os.Stat(path)
+	if err == nil {
+		return true
+	}
+	if os.IsNotExist(err) {
+		return false
+	}
+	return false
+}
+
+func (b Book) CoverURL() (*url.URL, error) {
+	// http: //covers.openlibrary.org/b/$key/$value-$size.jpg
+
+	localPath := path.Join("covers", fmt.Sprintf("%s.jpg", b.ISBN))
+
+	if PathExists(localPath) {
+		return url.Parse(localPath)
+	}
+
+	s := fmt.Sprintf("https://covers.openlibrary.org/b/isbn/%s-M.jpg", b.ISBN)
+	return url.Parse(s)
+
+}
+
+func (b Book) DownloadCover() error {
+	return nil
+}
+
+func BuildHTML(books []Book) (string, error) {
+	t, err := template.ParseFiles("template.html")
+
+	if err != nil {
+		return "", err
+	}
+
+	out := bytes.NewBuffer(nil)
+
+	err = t.Execute(out, books)
+
+	if err != nil {
+		return "", err
+	}
+
+	return out.String(), nil
+}
+
+func WriteFile(filename string, contents string) error {
+	f, err := os.Create(filename)
+	defer f.Close()
+
+	if err != nil {
 		return err
 	}
 
-	// *t = yamlTimeDur(td)
+	_, err = f.WriteString(contents)
+
+	if err != nil {
+		return err
+	}
+
 	return nil
+
 }
 
-type Book struct {
-	Author   string   `yaml:"author"`
-	Title    string   `yaml:"title"`
-	ISBN     string   `yaml:"isbn"`
-	DateRead DateRead `yaml: "date_read"`
-	Rating   float64  `yaml:"rating"`
-	Review   string   `yaml:"review"`
+func Build() error {
+	f, err := os.Open("book-log.org")
+
+	if err != nil {
+		return err
+	}
+
+	books, err := OrgTest(f)
+
+	if err != nil {
+		return err
+	}
+
+	sort.Sort(BooksByDateRead(books))
+
+	htmlOutput, err := BuildHTML(books)
+
+	if err != nil {
+		return err
+	}
+
+	// 	fmt.Println(htmlOutput)
+
+	err = WriteFile("output.html", htmlOutput)
+
+	if err != nil {
+		return err
+	}
+
+	return nil
 }
 
-func Build() {
-	fmt.Println("vim-go")
+func OrgTest(input io.Reader) ([]Book, error) {
+	books := []Book{}
+	conf := org.New()
+	d := conf.Parse(input, "")
+
+	for _, child := range d.Outline.Children {
+		for _, sub := range child.Children {
+			book := Book{
+				Title: sub.Headline.Title[0].String(),
+				Tags:  sub.Headline.Tags,
+			}
+
+			rest := bytes.NewBufferString("")
+
+			for _, c := range sub.Headline.Children {
+
+				switch t := c.(type) {
+				case org.PropertyDrawer:
+					author, ok := t.Get("AUTHOR")
+
+					if ok {
+						book.Author = author
+					}
+
+					rating, ok := t.Get("RATING")
+					if ok {
+						ratingInt, err := strconv.ParseInt(rating, 10, 8)
+						if err != nil {
+							return books, err
+						}
+						book.Rating = int(ratingInt)
+					}
+					isbn, ok := t.Get("ISBN")
+					if ok {
+						book.ISBN = isbn
+					}
+
+				case org.Paragraph:
+
+					s := t.String()
+
+					if strings.HasPrefix(s, "CLOSED") {
+						s = strings.TrimSpace(s)
+						dt, err := time.Parse("CLOSED: [2006-01-02 Mon 15:04]", s)
+						if err != nil {
+							return books, err
+						}
+						book.DateRead = DateRead{dt}
+						continue
+					}
+
+					fmt.Fprintln(rest, "")
+
+					fmt.Fprint(rest, "<p>")
+
+					for _, w := range t.Children {
+						switch wt := w.(type) {
+						case org.Text:
+							fmt.Fprintln(rest, wt)
+						case org.Emphasis:
+							fmt.Fprintf(rest, "<em>%s</em>", wt.Content[0].String())
+						case org.Timestamp:
+							fmt.Fprintln(rest, "timestamp par child", wt)
+						case org.RegularLink:
+							fmt.Fprintf(rest, `<a href="%s">%s</a>`, wt.URL, wt.Description)
+						case org.LineBreak:
+							continue
+						default:
+							fmt.Fprintln(rest, "def par", wt)
+						}
+					}
+					fmt.Fprintln(rest, "</p>")
+					fmt.Fprintln(rest, "")
+				case org.Block:
+					if t.Name == "QUOTE" {
+						fmt.Fprintln(rest, "<blockquote>")
+						for _, p := range t.Children {
+							fmt.Fprintf(rest, "%s<br><br>", p)
+						}
+						fmt.Fprintln(rest, "</blockquote>")
+					}
+				case org.List:
+					fmt.Fprint(rest, "<ul>")
+					for _, w := range t.Items {
+						switch wt := w.(type) {
+						case org.ListItem:
+							fmt.Fprintf(rest, `<li>BBB (%s) %s</li>`, wt.Bullet, wt.Children[0].String())
+						case org.DescriptiveListItem:
+							fmt.Fprintf(rest, `<li> desc %s</li>`, wt)
+						default:
+							fmt.Fprintln(rest, "list item def par child", wt)
+						}
+					}
+					fmt.Fprintln(rest, "</ul>")
+
+				case org.LineBreak:
+					fmt.Fprintln(rest, "")
+				case org.Timestamp:
+					fmt.Fprintln(rest, "BRUH")
+					panic("")
+				default:
+				}
+			}
+
+			book.Review = template.HTML(rest.String())
+			books = append(books, book)
+		}
+
+	}
+
+	return books, nil
+
 }