Skip to content

Commit

Permalink
🎨 ebook epub format
Browse files Browse the repository at this point in the history
  • Loading branch information
yann0917 committed Oct 9, 2022
1 parent 4432821 commit 9963df1
Show file tree
Hide file tree
Showing 8 changed files with 755 additions and 135 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ Available Commands:

注意:生成 PDF 的时候,操作过于频繁会触发 `496 NoCertificate` , 因此每次生成一次PDF sleep 0~5秒, 尽管如此,还是有极大可能触发操作频繁图形验证。

`dedao-dl dle 123 -t 1` 下载电子书,先通过 `dedao-dl ebook` 获取要下载的电子书 id, 下载格式, 1:html, 2:PDF文档, 3:epub(开发中) (default 1)
`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)

Expand Down
12 changes: 10 additions & 2 deletions cmd/download.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func init() {
rootCmd.AddCommand(dlEbookCmd)
downloadCmd.PersistentFlags().IntVarP(&downloadType, "downloadType", "t", 1, "下载格式, 1:mp3, 2:PDF文档, 3:markdown文档")
dlOdobCmd.PersistentFlags().IntVarP(&downloadType, "downloadType", "t", 1, "下载格式, 1:mp3, 2:PDF文档, 3:markdown文档")
dlEbookCmd.PersistentFlags().IntVarP(&downloadType, "downloadType", "t", 1, "下载格式, 1:html, 2:PDF文档, 3:epub(开发中)")
dlEbookCmd.PersistentFlags().IntVarP(&downloadType, "downloadType", "t", 1, "下载格式, 1:html, 2:PDF文档, 3:epub")
}

func download(cType string, id, aid int) error {
Expand Down Expand Up @@ -238,7 +238,15 @@ func download(cType string, id, aid int) error {
}

case 3:
err = errors.New("epub 格式开发中... ")
var opts utils.EpubOptions
opts.Title = title
opts.Author = detail.BookAuthor
opts.Description = detail.BookIntro

if err = utils.Svg2Epub(title, svgContent, opts); err != nil {
return err
}

return err
}

Expand Down
4 changes: 4 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ go 1.16

require (
github.com/JoshVarga/svgparser v0.0.0-20200804023048-5eaba627a7d1
github.com/PuerkitoBio/goquery v1.8.0
github.com/SebastiaanKlippert/go-wkhtmltopdf v1.7.2
github.com/bmaupin/go-epub v1.0.1
github.com/chromedp/cdproto v0.0.0-20220930195933-357956813629
github.com/chromedp/chromedp v0.8.6
github.com/gabriel-vasile/mimetype v1.3.1
github.com/go-resty/resty/v2 v2.7.0
github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/json-iterator/go v1.1.12
Expand All @@ -21,4 +24,5 @@ require (
github.com/spf13/cobra v1.5.0
github.com/stretchr/testify v1.8.0 // indirect
golang.org/x/net v0.0.0-20221004154528-8021a29435af // indirect
golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0
)
16 changes: 16 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
github.com/JoshVarga/svgparser v0.0.0-20200804023048-5eaba627a7d1 h1:RAQocNl+YQYGPt5yh4SR5zFUIHKrXnLhjIGhHO4Vwnc=
github.com/JoshVarga/svgparser v0.0.0-20200804023048-5eaba627a7d1/go.mod h1:tMmgUTWcco9d1ZmK7zjxuTv7XWZhyutXIsgu0uJ3gDw=
github.com/PuerkitoBio/goquery v1.8.0 h1:PJTF7AmFCFKk1N6V6jmKfrNH9tV5pNE6lZMkG0gta/U=
github.com/PuerkitoBio/goquery v1.8.0/go.mod h1:ypIiRMtY7COPGk+I/YbZLbxsxn9g5ejnI2HSMtkjZvI=
github.com/SebastiaanKlippert/go-wkhtmltopdf v1.7.2 h1:LORAatv6KuKheYq8HXehiwx3f/VGuzJBNSydUDQ98EM=
github.com/SebastiaanKlippert/go-wkhtmltopdf v1.7.2/go.mod h1:TY8r0gmwEL1c5Lbd66NgQCkL4ZjGDJCMVqvbbFvUx20=
github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c=
github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA=
github.com/bmaupin/go-epub v1.0.1 h1:LLbczYCXO/1sGpFd4/QRaDiEhevo4PYQxBQClZPRoco=
github.com/bmaupin/go-epub v1.0.1/go.mod h1:mBan+0WgVv5JbPNw1xfnfQoTRN9iPMKBshZwPOL0SY0=
github.com/chromedp/cdproto v0.0.0-20220924210414-0e3390be1777/go.mod h1:5Y4sD/eXpwrChIuxhSr/G20n9CdbCmoerOHnuAf0Zr0=
github.com/chromedp/cdproto v0.0.0-20220930195933-357956813629 h1:idJfU8ZgBwWWIJwlybyyrlVenTdHYEvlnaQvoagh6eE=
github.com/chromedp/cdproto v0.0.0-20220930195933-357956813629/go.mod h1:5Y4sD/eXpwrChIuxhSr/G20n9CdbCmoerOHnuAf0Zr0=
Expand All @@ -14,6 +20,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gabriel-vasile/mimetype v1.3.1 h1:qevA6c2MtE1RorlScnixeG0VA1H4xrXyhyX3oWBynNQ=
github.com/gabriel-vasile/mimetype v1.3.1/go.mod h1:fA8fi6KUiG7MgQQ+mEWotXoEOvmxRtOJlERCzSmRvr8=
github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY=
github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I=
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
Expand All @@ -22,6 +30,8 @@ github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
github.com/gobwas/ws v1.1.0 h1:7RFti/xnNkMJnrK7D1yQ/iCIB5OrrY/54/H930kIbHA=
github.com/gobwas/ws v1.1.0/go.mod h1:nzvNcVha5eUziGrbxFCo6qFIojQHjJV5cLYIbezhfL0=
github.com/gofrs/uuid v3.1.0+incompatible h1:q2rtkjaKT4YEr6E1kamy0Ha4RtepWlQBedyHx0uzKwA=
github.com/gofrs/uuid v3.1.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
Expand Down Expand Up @@ -82,9 +92,15 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/vincent-petithory/dataurl v0.0.0-20191104211930-d1553a71de50 h1:uxE3GYdXIOfhMv3unJKETJEhw78gvzuQqRX/rVirc2A=
github.com/vincent-petithory/dataurl v0.0.0-20191104211930-d1553a71de50/go.mod h1:FHafX5vmDzyP+1CQATJn7WFKc9CvnvxyvZy6I1MrG/U=
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20221004154528-8021a29435af h1:wv66FM3rLZGPdxpYL+ApnDe2HzHcTFta3z5nsc13wI4=
golang.org/x/net v0.0.0-20221004154528-8021a29435af/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0 h1:cu5kTvlzcw1Q5S9f5ip1/cpiB4nXvw1XYzFPGgzLUOY=
golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
Expand Down
199 changes: 199 additions & 0 deletions request/download.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
package request

import (
"context"
"fmt"
"io"
"net/http"
"os"
"time"

"golang.org/x/sync/errgroup"
"golang.org/x/sync/semaphore"
)

type GetDownload struct {
OnEachStart func(t *DownloadTask)
OnEachStop func(t *DownloadTask)
OnEachSkip func(t *DownloadTask)
Header http.Header
Client http.Client
}

type DownloadTask struct {
Link string
Path string
Err error
}

type DownloadTasks struct {
tasks []*DownloadTask
}

func Default() (g GetDownload) {
g.Header = make(http.Header)
g.Header.Set("user-agent", UserAgent)
return g
}

var one = Default()

func Download(dl *DownloadTask, timeout time.Duration) (err error) {
return one.Download(dl, timeout)
}
func DownloadWithContext(ctx context.Context, dl *DownloadTask) (err error) {
return one.DownloadWithContext(ctx, dl)
}
func Batch(tasks *DownloadTasks, concurrent int, eachTimeout time.Duration) *DownloadTasks {
return one.Batch(tasks, concurrent, eachTimeout)
}

func (g *GetDownload) Download(task *DownloadTask, timeout time.Duration) (err error) {
ctx, cancel := context.WithTimeout(context.TODO(), timeout)
defer cancel()

return g.DownloadWithContext(ctx, task)
}
func (g *GetDownload) DownloadWithContext(ctx context.Context, task *DownloadTask) (err error) {
if g.shouldSkip(ctx, task) {
if g.OnEachSkip != nil {
g.OnEachSkip(task)
}
return
}
if g.OnEachStart != nil {
g.OnEachStart(task)
}
defer func() {
task.Err = err
if g.OnEachStop != nil {
g.OnEachStop(task)
}
}()

f, err := os.OpenFile(task.Path, os.O_RDWR|os.O_CREATE, 0766)
if err != nil {
return
}
defer f.Close()

req, err := http.NewRequest(http.MethodGet, task.Link, nil)
if err != nil {
return
}
if s, e := f.Stat(); e == nil {
if s.Size() > 0 {
req.Header.Set("range", fmt.Sprintf("bytes=%d-", s.Size()))
}
}
for k := range g.Header {
req.Header[k] = g.Header[k]
}

rsp, err := g.Client.Do(req.WithContext(ctx))
if err != nil {
return
}
defer func() {
_, _ = io.Copy(io.Discard, rsp.Body)
_ = rsp.Body.Close()
}()

switch rsp.StatusCode {
case http.StatusPartialContent:
_, _ = f.Seek(0, io.SeekEnd)
case http.StatusOK, http.StatusRequestedRangeNotSatisfiable:
_ = f.Truncate(0)
default:
return fmt.Errorf("invalid status code %d(%s)", rsp.StatusCode, rsp.Status)
}

_, err = io.Copy(f, rsp.Body)
if err != nil {
return fmt.Errorf("copy error: %s", err)
}

mt, e := http.ParseTime(rsp.Header.Get("last-modified"))
if e == nil {
_ = os.Chtimes(task.Path, mt, mt)
}
ok, e := os.Create(task.Path + ".ok")
if e == nil {
_ = ok.Close()
}

return
}
func (g *GetDownload) Batch(tasks *DownloadTasks, concurrent int, eachTimeout time.Duration) *DownloadTasks {
var sema = semaphore.NewWeighted(int64(concurrent))
var grp errgroup.Group

tasks.ForEach(func(t *DownloadTask) {
_ = sema.Acquire(context.TODO(), 1)
grp.Go(func() (err error) {
defer sema.Release(1)
t.Err = g.Download(t, eachTimeout)
return
})
})

_ = grp.Wait()

return tasks
}
func (g *GetDownload) shouldSkip(ctx context.Context, task *DownloadTask) (skip bool) {
// check .ok file exist
fd, err := os.Open(task.Path + ".ok")
if err == nil {
_ = fd.Close()
return true
}

// check target file size
local, err := os.Stat(task.Path)
if err != nil {
return false
}

switch local.Size() {
case 0:
return false
default:
req, err := http.NewRequest(http.MethodHead, task.Link, nil)
if err == nil {
req.Header = g.Header
rsp, err := g.Client.Do(req.WithContext(ctx))
if err == nil {
_ = rsp.Body.Close()
return rsp.ContentLength == local.Size()
}
}
return false
}
}

func NewDownloadTask(link, path string) *DownloadTask {
return &DownloadTask{
Link: link,
Path: path,
}
}

func (d *DownloadTasks) Add(link, path string) {
for _, t := range d.tasks {
if t.Link == link && t.Path == path {
return
}
}
d.tasks = append(d.tasks, NewDownloadTask(link, path))
}

func (d *DownloadTasks) ForEach(f func(t *DownloadTask)) {
for _, t := range d.tasks {
f(t)
}
}

func NewDownloadTasks() *DownloadTasks {
return &DownloadTasks{}
}
Loading

0 comments on commit 9963df1

Please sign in to comment.