Skip to content

Commit

Permalink
🎨 odob add pdf
Browse files Browse the repository at this point in the history
  • Loading branch information
yann0917 committed Sep 4, 2023
1 parent 0539e90 commit 6ee2ce6
Show file tree
Hide file tree
Showing 8 changed files with 209 additions and 34 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
* 可查看已购买的锦囊
* 可查看知识城邦推荐话题精选内容
* 课程可生成PDF,文稿生成 Markdown 文档,也可生成 mp3 文件
* 每天听本书可下载音频,文稿生成 Markdown 文档
* 每天听本书可下载音频,文稿生成 pdf、Markdown 文档
* 电子书可下载 pdf
* 可切换登录账号

Expand Down Expand Up @@ -107,7 +107,7 @@ Available Commands:
course 获取我购买过课程
dl 下载已购买课程, 并转换成 PDF & 音频 & markdown
dle 下载电子书
dlo 下载每天听本书音频
dlo 下载每天听本书音频 & PDF & markdown
ebook 获取我的电子书架
help Help about any command
login 登录得到 pc 端 https://www.dedao.cn
Expand Down Expand Up @@ -208,7 +208,7 @@ Available Commands:

`dedao-dl dle 123 -t 1` 下载电子书,先通过 `dedao-dl ebook` 获取要下载的电子书 id, 下载格式, 1:html, 2:PDF文档, 3:epub (default 1)

`dedao-dl dlo 123 -t 1` 下载听书ID 123 的音频或文稿, 先通过 `dedao-dl odob` 获取要下载的听书 id, -t 下载格式, 1:mp3, 3:markdown文档 (default 1)
`dedao-dl dlo 123 -t 1` 下载听书ID 123 的音频或文稿, 先通过 `dedao-dl odob` 获取要下载的听书 id, -t 下载格式, 1:mp3, 2:PDF文档, 3:markdown文档 (default 1)

## References

Expand Down
69 changes: 41 additions & 28 deletions cmd/app/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import (
"strconv"
"strings"

"errors"

jsoniter "github.com/json-iterator/go"
"github.com/yann0917/dedao-dl/config"
"github.com/yann0917/dedao-dl/downloader"
Expand Down Expand Up @@ -132,8 +130,17 @@ func (d *OdobDownload) Download() error {
return errs[0]
}
case 2:
err := errors.New("得到 Web 端暂未开放每天听本书,PDF 无法下载。")
return err
path, err := utils.Mkdir(OutputDir, utils.FileName(fileName, ""), "PDF")
if err != nil {
return err
}
info, content, err2 := getArticleDetail(d.ID)
if err2 != nil {
return err2
}
res := ContentsToMarkdown(content)
return utils.Md2Pdf(path, info["title"].(string), []byte(res))

case 3:
// 下载 Markdown
path, err := utils.Mkdir(OutputDir, utils.FileName(fileName, ""), "MD")
Expand Down Expand Up @@ -550,30 +557,9 @@ func DownloadMarkdownCourse(id, aid int, path string) error {
}

func DownloadMarkdownAudioBook(id int, path string) error {
info := config.Instance.GetIDMap(CateAudioBook, id)
aliasID := info["audio_alias_id"].(string)
if aliasID == "" {
list, err := CourseList(CateAudioBook)
if err != nil {
return err
}
for _, v := range list.List {
if v.AudioDetail.SourceID == id {
aliasID = v.AudioDetail.AliasID
break
}
}
}
detail, err := OdobArticleDetail(aliasID)
if err != nil {
fmt.Println(err.Error())
return err
}

var content []services.Content
err = jsoniter.UnmarshalFromString(detail.Content, &content)
if err != nil {
return err
info, content, err2 := getArticleDetail(id)
if err2 != nil {
return err2
}

name := utils.FileName(info["title"].(string), "md")
Expand Down Expand Up @@ -611,3 +597,30 @@ func DownloadMarkdownAudioBook(id int, path string) error {
fmt.Printf("\033[32;1m%s\033[0m\n", "完成")
return nil
}

func getArticleDetail(id int) (info map[string]interface{}, content []services.Content, err error) {
info = config.Instance.GetIDMap(CateAudioBook, id)
aliasID := info["audio_alias_id"].(string)
if aliasID == "" {
list, err1 := CourseList(CateAudioBook)
if err1 != nil {
return nil, nil, err1
}
for _, v := range list.List {
if v.AudioDetail.SourceID == id {
aliasID = v.AudioDetail.AliasID
break
}
}
}
detail, err := OdobArticleDetail(aliasID)
if err != nil {
return nil, nil, err
}

err = jsoniter.UnmarshalFromString(detail.Content, &content)
if err != nil {
return nil, nil, err
}
return info, content, nil
}
2 changes: 1 addition & 1 deletion cmd/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ var downloadCmd = &cobra.Command{
var dlOdobCmd = &cobra.Command{
Use: "dlo",
Short: "下载每天听本书音频 & 文稿",
Long: `使用 dedao-dl dlo 下载每天听本书音频, 并转换成 PDF(未实现) & 音频 & markdown
Long: `使用 dedao-dl dlo 下载每天听本书音频, 并转换成 PDF & 音频 & markdown
-t 指定下载格式, 1:mp3, 2:PDF文档, 3:markdown文档, 默认 mp3`,
Example: "dedao-dl dlo 123 -t 1",
PreRunE: AuthFunc,
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ require (
github.com/gobwas/pool v0.2.1 // indirect
github.com/gobwas/ws v1.3.0 // indirect
github.com/gofrs/uuid v4.4.0+incompatible // indirect
github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ github.com/gobwas/ws v1.3.0/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/K
github.com/gofrs/uuid v3.1.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12 h1:uK3X/2mt4tbSGoHvbLBHUny7CKiuwUip3MArtukol4E=
github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
Expand Down
74 changes: 74 additions & 0 deletions utils/genPdf.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package utils

import (
"bytes"
"fmt"
"os"
"runtime"

"github.com/SebastiaanKlippert/go-wkhtmltopdf"
)

type PdfOption struct {
FileName string
CoverPath string
PageSize string
Toc bool
}

func (p *PdfOption) GenPdf(buf *bytes.Buffer) (err error) {
pdfg, _ := wkhtmltopdf.NewPDFGenerator()
page := wkhtmltopdf.NewPageReader(buf)
page.FooterFontSize.Set(10)
page.FooterRight.Set("[page]")
page.DisableSmartShrinking.Set(true)

page.EnableLocalFileAccess.Set(true)
pdfg.AddPage(page)

if p.CoverPath != "" {
pdfg.Cover.EnableLocalFileAccess.Set(true)

if runtime.GOOS == "windows" {
pdfg.Cover.Input = p.CoverPath
} else {
pdfg.Cover.Input = "file://" + p.CoverPath
}
}

pdfg.Dpi.Set(300)
if p.Toc {
pdfg.TOC.Include = true
pdfg.TOC.TocHeaderText.Set("目 录")
pdfg.TOC.HeaderFontSize.Set(18)

pdfg.TOC.TocLevelIndentation.Set(15)
pdfg.TOC.TocTextSizeShrink.Set(0.9)
pdfg.TOC.DisableDottedLines.Set(false)
pdfg.TOC.EnableTocBackLinks.Set(true)
}

pdfg.PageSize.Set(wkhtmltopdf.PageSizeA4)

pdfg.MarginTop.Set(15)
pdfg.MarginBottom.Set(15)
pdfg.MarginLeft.Set(15)
pdfg.MarginRight.Set(15)
err = pdfg.Create()
if err != nil {
fmt.Printf("pdfg create err: %#v\n", err)
return
}

// Write buffer contents to file on disk
err = pdfg.WriteFile(p.FileName)
if err != nil {
fmt.Printf("\033[31;1m%s\033[0m\n", "失败"+err.Error())
return
}
fmt.Printf("\033[32;1m%s\033[0m\n", "完成")
if p.CoverPath != "" {
err = os.Remove(p.CoverPath)
}
return
}
80 changes: 80 additions & 0 deletions utils/md2html.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package utils

import (
"bytes"
"fmt"
"path/filepath"

"github.com/gomarkdown/markdown"
"github.com/gomarkdown/markdown/html"
"github.com/gomarkdown/markdown/parser"
)

func Md2Pdf(path, title string, md []byte) (err error) {
if err != nil {
return err
}
title = FileName(title, "pdf")
filePreName := filepath.Join(path, title)
fileName, err := FilePath(filePreName, "", false)
if err != nil {
return err
}
buf := new(bytes.Buffer)

h := mdToHTML(md)
article := genHeadHtml() + string(h) + `
</body>
</html>`
buf.Write([]byte(article))
pdf := PdfOption{
FileName: fileName,
PageSize: "A4",
Toc: false,
}
fmt.Printf("正在生成文件:【\033[37;1m%s\033[0m】 ", title)
err = pdf.GenPdf(buf)
return
}

func genHeadHtml() (result string) {
result = `<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
@font-face { font-family: "FZFangSong-Z02"; src:local("FZFangSong-Z02"), url("https://imgcdn.umiwi.com/ttf/fangzhengfangsong_gbk.ttf"); }
@font-face { font-family: "FZKai-Z03"; src:local("FZFangSong-Z02S"), url("https://imgcdn.umiwi.com/ttf/0315911813008928624065681028886857980055.ttf"); }
@font-face { font-family: "FZKai-Z03"; src:local("FZKai-Z03"), url("https://imgcdn.umiwi.com/ttf/fangzhengkaiti_gbk.ttf"); }
@font-face { font-family: "PingFang SC"; src:local("PingFang SC"); }
@font-face { font-family: "DeDaoJinKai"; src:local("DeDaoJinKai"), url("https://imgcdn.umiwi.com/ttf/dedaojinkaiw03.ttf");}
@font-face { font-family: "Source Code Pro"; src:local("Source Code Pro"), url("https://imgcdn.umiwi.com/ttf/0315911806889993935644188722660020367983.ttf"); }
table, tr, td, th, tbody, thead, tfoot {page-break-inside: avoid !important;}
img { page-break-inside: avoid; max-width: 100% !important;}
img.epub-footnote { padding-right:5px;}
body {font-family: PingFang SC,Arial,sans-serif,Source Code Pro;color: #333;text-align: left;line-height: 1.8;}
em {font-style: normal;}
h2>code { background-color: rgb(255, 96, 2);padding: 0.5%;border-radius: 10%;color: white;}
p>em {color: rgb(255, 96, 2);}
</style>
</head>
<body>
`
return
}

func mdToHTML(md []byte) []byte {
// create markdown parser with extensions
extensions := parser.CommonExtensions | parser.AutoHeadingIDs | parser.NoEmptyLineBeforeBlock
p := parser.NewWithExtensions(extensions)
doc := p.Parse(md)

// create HTML renderer with extensions
htmlFlags := html.CommonFlags | html.HrefTargetBlank
opts := html.RendererOptions{Flags: htmlFlags}
renderer := html.NewRenderer(opts)

return markdown.Render(doc, renderer)
}
9 changes: 7 additions & 2 deletions utils/svg2html.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,13 @@ func Svg2Pdf(title string, svgContents []*SvgContent, toc []EbookToc) (err error
if err = WriteFileWithTrunc(coverPath, cover); err != nil {
return
}

err = genPdf(buf, fileName, coverPath)
pdf := PdfOption{
FileName: fileName,
CoverPath: coverPath,
PageSize: "A4",
Toc: true,
}
err = pdf.GenPdf(buf)
return
}

Expand Down

0 comments on commit 6ee2ce6

Please sign in to comment.