Skip to content

Commit d8f7fca

Browse files
authored
Merge pull request #26 from vinser/fb2-epub2
FB2 to EPUB2 on the fly converter
2 parents dc47a0a + 9bf5a5d commit d8f7fca

File tree

18 files changed

+987
-29
lines changed

18 files changed

+987
-29
lines changed

.gitignore

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1-
*~
21
/.vscode/
32
/apptree/
43
/cmd/flibgolite/books/
54
/cmd/flibgolite/config/
65
/cmd/flibgolite/dbdata/
76
/cmd/flibgolite/logs/
7+
/config/
8+
/dbdata/
9+
/logs/
810
/flibgolite*
9-
/workpad*
11+
/workpad*

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module github.com/vinser/flibgolite
33
go 1.22.5
44

55
require (
6+
github.com/google/uuid v1.6.0
67
github.com/jmoiron/sqlx v1.4.0
78
github.com/kardianos/service v1.2.2
89
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
@@ -15,7 +16,6 @@ require (
1516

1617
require (
1718
github.com/dustin/go-humanize v1.0.1 // indirect
18-
github.com/google/uuid v1.6.0 // indirect
1919
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
2020
github.com/mattn/go-isatty v0.0.20 // indirect
2121
github.com/ncruces/go-strftime v0.1.9 // indirect

pkg/config/config.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,10 @@ type Config struct {
3838
LEVEL string `yaml:"LEVEL"`
3939
}
4040
OPDS struct {
41-
PORT int `yaml:"PORT"`
42-
TITLE string `yaml:"TITLE"`
43-
PAGE_SIZE int `yaml:"PAGE_SIZE"`
41+
PORT int `yaml:"PORT"`
42+
TITLE string `yaml:"TITLE"`
43+
PAGE_SIZE int `yaml:"PAGE_SIZE"`
44+
NO_CONVERSION bool `yaml:"NO_CONVERSION"`
4445
}
4546
locales.Locales
4647
}

pkg/config/config.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ library:
22
# Book folders
33
STOCK: "books/stock" # Book stock
44
TRASH: "books/trash" # Error and duplicate files and archives will be moved to this folder
5-
# NEW: "books/new" # Uncomment the line to have separate folder for new acquired books
5+
#NEW: "books/new" # Uncomment the line to have separate folder for new acquired books
66

77
genres:
88
TREE_FILE: "config/genres.xml"
@@ -35,6 +35,8 @@ opds:
3535
TITLE: "FLib Go Go Go!!!"
3636
# OPDS feeds entries page size
3737
PAGE_SIZE: 30
38+
# Do not convert FB2 to EPUB format
39+
#NO_CONVERSION: true
3840

3941
locales:
4042
# Locales folder. You can add your own locale file there like en.yml, ru.yml, uk.yml

pkg/conv/LICENSE

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
Substantial code portions was borrowed from https://github.com/reinventer/fb2epub under this MIT License
2+
3+
Copyright (c) 2017 Dmitry Panov
4+
5+
Permission is hereby granted, free of charge, to any person obtaining
6+
a copy of this software and associated documentation files (the
7+
"Software"), to deal in the Software without restriction, including
8+
without limitation the rights to use, copy, modify, merge, publish,
9+
distribute, sublicense, and/or sell copies of the Software, and to
10+
permit persons to whom the Software is furnished to do so, subject to
11+
the following conditions:
12+
13+
The above copyright notice and this permission notice shall be
14+
included in all copies or substantial portions of the Software.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

pkg/conv/epub2/add.go

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
package epub2
2+
3+
import (
4+
"encoding/base64"
5+
"strconv"
6+
)
7+
8+
// AddMetadataSubject adds subject to metadata
9+
func (e *EPUB) AddMetadataSubject(subj string) {
10+
e.Metadata += "<dc:subject>" + subj + "</dc:subject>\n"
11+
}
12+
13+
// AddMetadataAuthor adds author to metadata
14+
func (e *EPUB) AddMetadataAuthor(name, sort string) {
15+
e.Metadata += `<dc:creator opf:file-as="` + sort + `" opf:role="aut" xmlns:opf="http://www.idpf.org/2007/opf">` + name + `</dc:creator>` + "\n"
16+
}
17+
18+
// AddMetadataDescription adds description to metadata
19+
func (e *EPUB) AddMetadataDescription(desc string) {
20+
e.Metadata += "<dc:description>" + desc + "</dc:description>\n"
21+
}
22+
23+
// AddMetadataTitle adds title to metadata
24+
func (e *EPUB) AddMetadataTitle(title string) {
25+
e.Title = title
26+
e.Metadata += "<dc:title>" + title + "</dc:title>\n"
27+
}
28+
29+
// AddMetadataLanguage adds language to metadata
30+
func (e *EPUB) AddMetadataLanguage(lang string) {
31+
e.Lang = lang
32+
e.Metadata += `<dc:language xsi:type="dcterms:RFC3066">` + lang + `</dc:language>` + "\n"
33+
}
34+
35+
// AddMetadataCover add cover to metadata
36+
func (e *EPUB) AddMetadataCover(imageName string) {
37+
e.Metadata += `<meta name="cover" content="` + imageName + `" />` + "\n"
38+
}
39+
40+
func (e *EPUB) AddItem(itemName, guideType, content string) error {
41+
e.Manifest += `<item id="` + itemName + `" href="` + itemName + `.xhtml" media-type="application/xhtml+xml" />` + "\n"
42+
e.Spine += `<itemref idref="` + itemName + `" />` + "\n"
43+
44+
data := struct {
45+
Title string
46+
Content string
47+
Type string
48+
}{
49+
Title: e.Title,
50+
Content: content,
51+
Type: guideType,
52+
}
53+
return e.execTemplate("OEBPS/"+itemName+".xhtml", "page.tmpl", data)
54+
}
55+
56+
func (e *EPUB) AddBinary(id, contentType, base64Content string) error {
57+
e.Manifest += `<item id="` + id + `" href="` + id + `" media-type="` + contentType + `" />` + "\n"
58+
data, err := base64.StdEncoding.DecodeString(base64Content)
59+
if err != nil {
60+
return err
61+
}
62+
63+
f, err := e.zw.Create("OEBPS/" + id)
64+
if err != nil {
65+
return err
66+
}
67+
68+
_, err = f.Write(data)
69+
return err
70+
}
71+
72+
func (e *EPUB) AddOPF() error {
73+
return e.execTemplate("OEBPS/content.opf", "content.tmpl", e)
74+
}
75+
76+
func (e *EPUB) AddTOC() error {
77+
toc := ""
78+
prevDepth := 1
79+
for i, t := range e.Toc {
80+
// fmt.Println(t)
81+
switch {
82+
case i == 0 || t.Depth > prevDepth:
83+
prevDepth = t.Depth
84+
case t.Depth == prevDepth:
85+
toc += `
86+
</navPoint>
87+
`
88+
case t.Depth < prevDepth:
89+
toc += `
90+
</navPoint>
91+
</navPoint>
92+
`
93+
prevDepth = t.Depth
94+
}
95+
toc += `
96+
<navPoint playOrder="` + strconv.Itoa(t.Order) + `" id="` + t.Id + `">
97+
<navLabel>
98+
<text>` + t.Text + `</text>
99+
</navLabel>
100+
<content src="` + t.Src + `" />
101+
`
102+
}
103+
104+
for i := 1; i <= prevDepth; i++ {
105+
toc += `
106+
</navPoint>
107+
`
108+
}
109+
110+
data := struct {
111+
Lang string
112+
Title string
113+
Toc string
114+
}{
115+
Lang: e.Lang,
116+
Title: e.Title,
117+
Toc: toc,
118+
}
119+
return e.execTemplate("OEBPS/toc.ncx", "toc.tmpl", data)
120+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<container version="1.0" xmlns="urn:oasis:names:tc:opendocument:xmlns:container">
3+
<rootfiles>
4+
<rootfile full-path="OEBPS/content.opf" media-type="application/oebps-package+xml" />
5+
</rootfiles>
6+
</container>
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
body {
2+
font-family: serif;
3+
}
4+
5+
.epigraph
6+
{
7+
font-style: italic;
8+
page-break-inside:avoid;
9+
margin: 0.5em 0px;
10+
margin-bottom: 1em;
11+
font-size:0.9em;
12+
}
13+
14+
.epigraph .text-author
15+
{
16+
margin-left: 1em;
17+
font-size: 0.85em;
18+
margin: 0.6em 0px;
19+
margin-left: 2em;
20+
}
21+
22+
body.cover {
23+
margin: 0px;
24+
padding: 0px;
25+
}
26+
27+
div.cover {
28+
text-align: center;
29+
page-break-after: always;
30+
}
31+
32+
img.coverimage {
33+
width: 100%;
34+
height: 100%;
35+
}
36+
37+
img {
38+
max-width: 95%;
39+
}
40+
41+
div.image {
42+
padding: 3px;
43+
text-align: center;
44+
}
45+
46+
div.title {
47+
page-break-after: avoid;
48+
page-break-inside: avoid;
49+
font-weight: bold;
50+
margin: 1em 0px 0.5em 0px;
51+
font-size: 1.4em;
52+
text-align: center;
53+
}
54+
55+
div.section div.title {
56+
font-size: 1.2em;
57+
text-align: center;
58+
}
59+
60+
div.subtitle {
61+
font-style: italic;
62+
page-break-after: avoid;
63+
page-break-inside: avoid;
64+
font-weight: bold;
65+
text-indent: 0px;
66+
margin: 0.5em 2em;
67+
text-align: center;
68+
}
69+
70+
a {
71+
vertical-align: super;
72+
line-height: 0.1;
73+
font-size: 0.7em;
74+
}
75+
76+
div.poem {
77+
margin: 0.5em 15% 0.5em 15%;
78+
text-align: center;
79+
}
80+
81+
div.stanza {
82+
page-break-inside: avoid;
83+
margin: 0.5em 0px;
84+
justify: left;
85+
}
86+
87+
p.v {
88+
padding-left: 1em;
89+
text-indent: -1em;
90+
margin: 0px;
91+
justify: left;
92+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
application/epub+zip
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<package version="2.0" unique-identifier="BookID" xmlns="http://www.idpf.org/2007/opf">
3+
<metadata xmlns="http://www.idpf.org/2007/opf" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dcterms="http://purl.org/dc/terms/">
4+
{{.Metadata}}
5+
<dc:identifier id="BookID">urn:uuid:{{.UUID}}</dc:identifier>
6+
</metadata>
7+
<manifest>
8+
{{.Manifest}}
9+
<item id="ncx" href="toc.ncx" media-type="application/x-dtbncx+xml" /></manifest>
10+
<spine toc="ncx">
11+
{{.Spine}}
12+
</spine>
13+
</package>

0 commit comments

Comments
 (0)