diff --git a/cmd/app/download.go b/cmd/app/download.go index f4f80b15..59b54712 100644 --- a/cmd/app/download.go +++ b/cmd/app/download.go @@ -52,7 +52,7 @@ func (d *CourseDownload) Download() error { switch d.DownloadType { case 1: // mp3 downloadData := extractDownloadData(course, articles, d.AID, 1) - errors := make([]error, 0) + errs := make([]error, 0) path, err := utils.Mkdir(OutputDir, utils.FileName(course.ClassInfo.Name, ""), "MP3") if err != nil { @@ -65,17 +65,17 @@ func (d *CourseDownload) Download() error { } stream := datum.Enid if err := downloader.Download(datum, stream, path); err != nil { - errors = append(errors, err) + errs = append(errs, err) } } - if len(errors) > 0 { - return errors[0] + if len(errs) > 0 { + return errs[0] } case 2: // 下载 PDF downloadData := extractDownloadData(course, articles, d.AID, 2) - errors := make([]error, 0) + errs := make([]error, 0) path, err := utils.Mkdir(OutputDir, utils.FileName(course.ClassInfo.Name, ""), "PDF") if err != nil { @@ -85,11 +85,11 @@ func (d *CourseDownload) Download() error { cookies := LoginedCookies() for _, datum := range downloadData.Data { if err := downloader.PrintToPDF(datum, cookies, path); err != nil { - errors = append(errors, err) + errs = append(errs, err) } } - if len(errors) > 0 { - return errors[0] + if len(errs) > 0 { + return errs[0] } case 3: // 下载 Markdown @@ -97,7 +97,7 @@ func (d *CourseDownload) Download() error { if err != nil { return err } - if err := DownloadMarkdown(CateCourse, d.ID, d.AID, path); err != nil { + if err := DownloadMarkdownCourse(d.ID, d.AID, path); err != nil { return err } } @@ -114,7 +114,7 @@ func (d *OdobDownload) Download() error { } downloadData.Type = "audio" downloadData.Data = extractOdobDownloadData(d.ID) - errors := make([]error, 0) + errs := make([]error, 0) path, err := utils.Mkdir(OutputDir, utils.FileName(fileName, ""), "MP3") if err != nil { return err @@ -125,11 +125,11 @@ func (d *OdobDownload) Download() error { } stream := datum.Enid if err := downloader.Download(datum, stream, path); err != nil { - errors = append(errors, err) + errs = append(errs, err) } } - if len(errors) > 0 { - return errors[0] + if len(errs) > 0 { + return errs[0] } case 2: err := errors.New("得到 Web 端暂未开放每天听本书,PDF 无法下载。") @@ -140,7 +140,7 @@ func (d *OdobDownload) Download() error { if err != nil { return err } - if err := DownloadMarkdown(CateAudioBook, d.ID, 0, path); err != nil { + if err := DownloadMarkdownAudioBook(d.ID, path); err != nil { return err } } @@ -384,59 +384,17 @@ func ContentsToMarkdown(contents []services.Content) (res string) { res = strings.TrimRight(res, "> \r\n") res += "\r\n\r\n" case "paragraph": - // map 转结构体 - tmpJson, err := jsoniter.Marshal(content.Contents) + resP, err := paragraphToMarkDown(content.Contents) if err != nil { return } - cont := services.Contents{} - err = jsoniter.Unmarshal(tmpJson, &cont) - if err != nil { - return "" - } - for _, item := range cont { - subContent := strings.Trim(item.Text.Content, " ") - switch item.Type { - case "text": - if item.Text.Bold { - res += " **" + subContent + "** " - } else if item.Text.Highlight { - res += " *" + subContent + "* " - } else { - res += subContent - } - } - } - res = strings.Trim(res, " ") - res = strings.Trim(res, "\r\n") - res += "\r\n\r\n" + res += resP case "list": - tmpJson, err := jsoniter.Marshal(content.Contents) + resL, err := listToMarkdown(content.Contents) if err != nil { return } - var cont []services.Contents - err = jsoniter.Unmarshal(tmpJson, &cont) - if err != nil { - return "" - } - - for _, item := range cont { - for _, item := range item { - subContent := strings.Trim(item.Text.Content, " ") - switch item.Type { - case "text": - if item.Text.Bold { - res += "* **" + subContent + "** " - } else if item.Text.Highlight { - res += "* *" + subContent + "* " - } else { - res += "* " + subContent - } - } - } - res += "\r\n\r\n" - } + res += resL case "elite": // 划重点 res += getMdHeader(2) + "划重点\r\n\r\n" + content.Text + "\r\n\r\n" @@ -451,6 +409,65 @@ func ContentsToMarkdown(contents []services.Content) (res string) { return } +func paragraphToMarkDown(content interface{}) (res string, err error) { + tmpJson, err := jsoniter.Marshal(content) + if err != nil { + return + } + cont := services.Contents{} + err = jsoniter.Unmarshal(tmpJson, &cont) + if err != nil { + return + } + for _, item := range cont { + subContent := strings.Trim(item.Text.Content, " ") + switch item.Type { + case "text": + if item.Text.Bold { + res += " **" + subContent + "** " + } else if item.Text.Highlight { + res += " *" + subContent + "* " + } else { + res += subContent + } + } + } + res = strings.Trim(res, " ") + res = strings.Trim(res, "\r\n") + res += "\r\n\r\n" + return +} + +func listToMarkdown(content interface{}) (res string, err error) { + tmpJson, err := jsoniter.Marshal(content) + if err != nil { + return + } + var cont []services.Contents + err = jsoniter.Unmarshal(tmpJson, &cont) + if err != nil { + return + } + + for _, item := range cont { + for _, item := range item { + subContent := strings.Trim(item.Text.Content, " ") + switch item.Type { + case "text": + if item.Text.Bold { + res += "* **" + subContent + "** " + } else if item.Text.Highlight { + res += "* *" + subContent + "* " + } else { + res += "* " + subContent + } + } + } + res += "\r\n\r\n" + } + return +} + func articleCommentsToMarkdown(contents []services.ArticleComment) (res string) { res = getMdHeader(2) + "热门留言\r\n\r\n" for _, content := range contents { @@ -478,84 +495,16 @@ func getMdHeader(level int) string { return "" } -func DownloadMarkdown(cType string, id, aid int, path string) error { - switch cType { - case CateCourse: - list, err := ArticleList(id, "") - if err != nil { - return err - } - for _, v := range list.List { - if aid > 0 && v.ID != aid { - continue - } - detail, enId, err := ArticleDetail(id, v.ID) - if err != nil { - fmt.Println(err.Error()) - return err - } - - var content []services.Content - err = jsoniter.UnmarshalFromString(detail.Content, &content) - if err != nil { - return err - } - - name := utils.FileName(v.Title, "md") - fileName := filepath.Join(path, name) - fmt.Printf("正在生成文件:【\033[37;1m%s\033[0m】 ", name) - _, exist, err := utils.FileSize(fileName) - - if err != nil { - fmt.Printf("\033[31;1m%s\033[0m\n", "失败"+err.Error()) - return err - } - - if exist { - fmt.Printf("\033[33;1m%s\033[0m\n", "已存在") - return nil - } - - res := ContentsToMarkdown(content) - // 添加留言 - commentList, err := ArticleCommentList(enId, "like", 1, 20) - if err == nil { - res += articleCommentsToMarkdown(commentList.List) - } - - f, err := os.OpenFile(fileName, os.O_CREATE|os.O_WRONLY, 0644) - if err != nil { - fmt.Printf("\033[31;1m%s\033[0m\n", "失败"+err.Error()) - return err - } - _, err = f.WriteString(res) - if err != nil { - fmt.Printf("\033[31;1m%s\033[0m\n", "失败"+err.Error()) - return err - } - if err = f.Close(); err != nil { - if err != nil { - return err - } - } - fmt.Printf("\033[32;1m%s\033[0m\n", "完成") - } - case CateAudioBook: - info := config.Instance.GetIDMap(CateAudioBook, id) - aliasID := info["audio_alias_id"].(string) - if aliasID == "" { - list, err := CourseList(cType) - if err != nil { - return err - } - for _, v := range list.List { - if v.AudioDetail.SourceID == id { - aliasID = v.AudioDetail.AliasID - break - } - } +func DownloadMarkdownCourse(id, aid int, path string) error { + list, err := ArticleList(id, "") + if err != nil { + return err + } + for _, v := range list.List { + if aid > 0 && v.ID != aid { + continue } - detail, err := OdobArticleDetail(aliasID) + detail, enId, err := ArticleDetail(id, v.ID) if err != nil { fmt.Println(err.Error()) return err @@ -567,7 +516,7 @@ func DownloadMarkdown(cType string, id, aid int, path string) error { return err } - name := utils.FileName(info["title"].(string), "md") + name := utils.FileName(v.Title, "md") fileName := filepath.Join(path, name) fmt.Printf("正在生成文件:【\033[37;1m%s\033[0m】 ", name) _, exist, err := utils.FileSize(fileName) @@ -583,6 +532,11 @@ func DownloadMarkdown(cType string, id, aid int, path string) error { } res := ContentsToMarkdown(content) + // 添加留言 + commentList, err := ArticleCommentList(enId, "like", 1, 20) + if err == nil { + res += articleCommentsToMarkdown(commentList.List) + } f, err := os.OpenFile(fileName, os.O_CREATE|os.O_WRONLY, 0644) if err != nil { @@ -600,11 +554,69 @@ func DownloadMarkdown(cType string, id, aid int, path string) error { } } fmt.Printf("\033[32;1m%s\033[0m\n", "完成") + } + return nil +} + +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 + } - case CateAce: + var content []services.Content + err = jsoniter.UnmarshalFromString(detail.Content, &content) + if err != nil { + return err + } + + name := utils.FileName(info["title"].(string), "md") + fileName := filepath.Join(path, name) + fmt.Printf("正在生成文件:【\033[37;1m%s\033[0m】 ", name) + _, exist, err := utils.FileSize(fileName) + + if err != nil { + fmt.Printf("\033[31;1m%s\033[0m\n", "失败"+err.Error()) + return err + } + if exist { + fmt.Printf("\033[33;1m%s\033[0m\n", "已存在") + return nil } - return nil + res := ContentsToMarkdown(content) + f, err := os.OpenFile(fileName, os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + fmt.Printf("\033[31;1m%s\033[0m\n", "失败"+err.Error()) + return err + } + _, err = f.WriteString(res) + if err != nil { + fmt.Printf("\033[31;1m%s\033[0m\n", "失败"+err.Error()) + return err + } + if err = f.Close(); err != nil { + if err != nil { + return err + } + } + fmt.Printf("\033[32;1m%s\033[0m\n", "完成") + return nil } diff --git a/parse/m3u8.go b/parse/m3u8.go deleted file mode 100644 index 394589d4..00000000 --- a/parse/m3u8.go +++ /dev/null @@ -1,271 +0,0 @@ -package parse - -// Partial reference https://github.com/grafov/m3u8/blob/master/reader.go -import ( - "bufio" - "errors" - "fmt" - "io" - "regexp" - "strconv" - "strings" -) - -type ( - // PlaylistType Playlist Type - PlaylistType string - // CryptMethod Crypt Method - CryptMethod string -) - -const ( - // PlaylistTypeVOD VOD - PlaylistTypeVOD PlaylistType = "VOD" - // PlaylistTypeEvent EVENT - PlaylistTypeEvent PlaylistType = "EVENT" - // CryptMethodAES AES-128 - CryptMethodAES CryptMethod = "AES-128" - // CryptMethodNONE NONE - CryptMethodNONE CryptMethod = "NONE" -) - -// regex pattern for extracting `key=value` parameters from a line -var linePattern = regexp.MustCompile(`([a-zA-Z-]+)=("[^"]+"|[^",]+)`) - -// M3u8 M3U8 -type M3u8 struct { - MediaSequence uint64 // Default 0, #EXT-X-MEDIA-SEQUENCE:sequence - Segments []*Segment - MasterPlaylist []*MasterPlaylist - Keys map[int]*Key - PlaylistType PlaylistType // VOD or EVENT - TargetDuration float64 // #EXT-X-TARGETDURATION:duration - Version int8 // EXT-X-VERSION:version - EndList bool // #EXT-X-ENDLIST -} - -// Segment EXTINF: -type Segment struct { - URI string - KeyIndex int - Title string // #EXTINF: duration, - Duration float32 // #EXTINF: duration,<title> - Length uint64 // #EXT-X-BYTERANGE: length[@offset] - Offset uint64 // #EXT-X-BYTERANGE: length[@offset] -} - -// MasterPlaylist master playlist -// -// #EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=240000,RESOLUTION=416x234,CODECS="avc1.42e00a,mp4a.40.2" -type MasterPlaylist struct { - URI string - BandWidth uint32 - Resolution string - Codecs string - ProgramID uint32 -} - -// Key EXT-X-KEY: -// #EXT-X-KEY:METHOD=AES-128,URI="key.key",KEYFORMAT="identity",IV=0xc2b6c3bc4cc3afc2962d737f2142c29d -type Key struct { - // 'AES-128' or 'NONE' - // If the encryption method is NONE, the URI and the IV attributes MUST NOT be present - Method CryptMethod - URI string - IV string -} - -func parse(reader io.Reader) (*M3u8, error) { - s := bufio.NewScanner(reader) - var lines []string - for s.Scan() { - lines = append(lines, s.Text()) - } - - var ( - i = 0 - count = len(lines) - m3u8 = &M3u8{ - Keys: make(map[int]*Key), - } - keyIndex = 0 - - key *Key - seg *Segment - extInf bool - extByte bool - ) - - for ; i < count; i++ { - line := strings.TrimSpace(lines[i]) - if i == 0 { - if "#EXTM3U" != line { - return nil, fmt.Errorf("invalid m3u8, missing #EXTM3U in line 1") - } - continue - } - switch { - case line == "": - continue - case strings.HasPrefix(line, "#EXT-X-PLAYLIST-TYPE:"): - if _, err := fmt.Sscanf(line, "#EXT-X-PLAYLIST-TYPE:%s", &m3u8.PlaylistType); err != nil { - return nil, err - } - isValid := m3u8.PlaylistType == "" || m3u8.PlaylistType == PlaylistTypeVOD || m3u8.PlaylistType == PlaylistTypeEvent - if !isValid { - return nil, fmt.Errorf("invalid playlist type: %s, line: %d", m3u8.PlaylistType, i+1) - } - case strings.HasPrefix(line, "#EXT-X-TARGETDURATION:"): - if _, err := fmt.Sscanf(line, "#EXT-X-TARGETDURATION:%f", &m3u8.TargetDuration); err != nil { - return nil, err - } - case strings.HasPrefix(line, "#EXT-X-MEDIA-SEQUENCE:"): - if _, err := fmt.Sscanf(line, "#EXT-X-MEDIA-SEQUENCE:%d", &m3u8.MediaSequence); err != nil { - return nil, err - } - case strings.HasPrefix(line, "#EXT-X-VERSION:"): - if _, err := fmt.Sscanf(line, "#EXT-X-VERSION:%d", &m3u8.Version); err != nil { - return nil, err - } - // Parse master playlist - case strings.HasPrefix(line, "#EXT-X-STREAM-INF:"): - mp, err := parseMasterPlaylist(line) - if err != nil { - return nil, err - } - i++ - mp.URI = lines[i] - if mp.URI == "" || strings.HasPrefix(mp.URI, "#") { - return nil, fmt.Errorf("invalid EXT-X-STREAM-INF URI, line: %d", i+1) - } - m3u8.MasterPlaylist = append(m3u8.MasterPlaylist, mp) - continue - case strings.HasPrefix(line, "#EXTINF:"): - if extInf { - return nil, fmt.Errorf("duplicate EXTINF: %s, line: %d", line, i+1) - } - if seg == nil { - seg = new(Segment) - } - var s string - if _, err := fmt.Sscanf(line, "#EXTINF:%s", &s); err != nil { - return nil, err - } - if strings.Contains(s, ",") { - split := strings.Split(s, ",") - seg.Title = split[1] - s = split[0] - } - df, err := strconv.ParseFloat(s, 32) - if err != nil { - return nil, err - } - seg.Duration = float32(df) - seg.KeyIndex = keyIndex - extInf = true - case strings.HasPrefix(line, "#EXT-X-BYTERANGE:"): - if extByte { - return nil, fmt.Errorf("duplicate EXT-X-BYTERANGE: %s, line: %d", line, i+1) - } - if seg == nil { - seg = new(Segment) - } - var b string - if _, err := fmt.Sscanf(line, "#EXT-X-BYTERANGE:%s", &b); err != nil { - return nil, err - } - if b == "" { - return nil, fmt.Errorf("invalid EXT-X-BYTERANGE, line: %d", i+1) - } - if strings.Contains(b, "@") { - split := strings.Split(b, "@") - offset, err := strconv.ParseUint(split[1], 10, 64) - if err != nil { - return nil, err - } - seg.Offset = uint64(offset) - b = split[0] - } - length, err := strconv.ParseUint(b, 10, 64) - if err != nil { - return nil, err - } - seg.Length = uint64(length) - extByte = true - // Parse segments URI - case !strings.HasPrefix(line, "#"): - if extInf { - if seg == nil { - return nil, fmt.Errorf("invalid line: %s", line) - } - seg.URI = line - extByte = false - extInf = false - m3u8.Segments = append(m3u8.Segments, seg) - seg = nil - continue - } - // Parse key - case strings.HasPrefix(line, "#EXT-X-KEY"): - params := parseLineParameters(line) - if len(params) == 0 { - return nil, fmt.Errorf("invalid EXT-X-KEY: %s, line: %d", line, i+1) - } - method := CryptMethod(params["METHOD"]) - if method != "" && method != CryptMethodAES && method != CryptMethodNONE { - return nil, fmt.Errorf("invalid EXT-X-KEY method: %s, line: %d", method, i+1) - } - keyIndex++ - key = new(Key) - key.Method = method - key.URI = params["URI"] - key.IV = params["IV"] - m3u8.Keys[keyIndex] = key - case line == "#EndList": - m3u8.EndList = true - default: - continue - } - } - - return m3u8, nil -} - -func parseMasterPlaylist(line string) (*MasterPlaylist, error) { - params := parseLineParameters(line) - if len(params) == 0 { - return nil, errors.New("empty parameter") - } - mp := new(MasterPlaylist) - for k, v := range params { - switch { - case k == "BANDWIDTH": - v, err := strconv.ParseUint(v, 10, 32) - if err != nil { - return nil, err - } - mp.BandWidth = uint32(v) - case k == "RESOLUTION": - mp.Resolution = v - case k == "PROGRAM-ID": - v, err := strconv.ParseUint(v, 10, 32) - if err != nil { - return nil, err - } - mp.ProgramID = uint32(v) - case k == "CODECS": - mp.Codecs = v - } - } - return mp, nil -} - -// parseLineParameters extra parameters in string `line` -func parseLineParameters(line string) map[string]string { - r := linePattern.FindAllStringSubmatch(line, -1) - params := make(map[string]string) - for _, arr := range r { - params[arr[1]] = strings.Trim(arr[2], "\"") - } - return params -} diff --git a/parse/parser.go b/parse/parser.go deleted file mode 100644 index 67b23931..00000000 --- a/parse/parser.go +++ /dev/null @@ -1,67 +0,0 @@ -package parse - -import ( - "errors" - "fmt" - "net/url" - - "github.com/yann0917/dedao-dl/request" - "github.com/yann0917/dedao-dl/utils" -) - -type Result struct { - URL *url.URL - M3u8 *M3u8 - Keys map[int]string -} - -// FromURL -func FromURL(link string) (*Result, error) { - u, err := url.Parse(link) - if err != nil { - return nil, err - } - link = u.String() - body, err := request.Get(link) - if err != nil { - return nil, fmt.Errorf("request m3u8 URL failed: %s", err.Error()) - } - //noinspection GoUnhandledErrorResult - defer body.Close() - m3u8, err := parse(body) - if err != nil { - return nil, err - } - if len(m3u8.MasterPlaylist) != 0 { - sf := m3u8.MasterPlaylist[0] - return FromURL(utils.ResolveURL(u, sf.URI)) - } - if len(m3u8.Segments) == 0 { - return nil, errors.New("can not found any TS file description") - } - result := &Result{ - URL: u, - M3u8: m3u8, - Keys: make(map[int]string), - } - - for idx, key := range m3u8.Keys { - switch { - case key.Method == "" || key.Method == CryptMethodNONE: - continue - case key.Method == CryptMethodAES: - // Request URL to extract decryption key - keyURL := key.URI - keyURL = utils.ResolveURL(u, keyURL) - resp, err := request.HTTPGet(keyURL) - if err != nil { - return nil, fmt.Errorf("extract key failed: %s", err.Error()) - } - fmt.Println("decryption key: ", string(resp)) - result.Keys[idx] = string(resp) - default: - return nil, fmt.Errorf("unknown or unsupported cryption method: %s", key.Method) - } - } - return result, nil -} diff --git a/request/download.go b/request/download.go index 60b0bcd6..816da70a 100644 --- a/request/download.go +++ b/request/download.go @@ -41,9 +41,11 @@ 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) } @@ -54,6 +56,7 @@ func (g *GetDownload) Download(task *DownloadTask, timeout time.Duration) (err e 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 { @@ -108,22 +111,21 @@ func (g *GetDownload) DownloadWithContext(ctx context.Context, task *DownloadTas return fmt.Errorf("invalid status code %d(%s)", rsp.StatusCode, rsp.Status) } - _, err = io.Copy(f, rsp.Body) - if err != nil { + if _, err := io.Copy(f, rsp.Body); err != nil { return fmt.Errorf("copy error: %s", err) } - mt, e := http.ParseTime(rsp.Header.Get("last-modified")) - if e == nil { + if mt, e := http.ParseTime(rsp.Header.Get("last-modified")); e == nil { _ = os.Chtimes(task.Path, mt, mt) } - ok, e := os.Create(task.Path + ".ok") - if e == nil { + + if ok, e := os.Create(task.Path + ".ok"); 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 @@ -141,6 +143,7 @@ func (g *GetDownload) Batch(tasks *DownloadTasks, concurrent int, eachTimeout ti return tasks } + func (g *GetDownload) shouldSkip(ctx context.Context, task *DownloadTask) (skip bool) { // check .ok file exist fd, err := os.Open(task.Path + ".ok") diff --git a/utils/html2epub.go b/utils/html2epub.go index f92eaef7..d669b9fa 100644 --- a/utils/html2epub.go +++ b/utils/html2epub.go @@ -155,7 +155,7 @@ func (h *HtmlToEpub) saveImages(doc *goquery.Document) map[string]string { return } - localFile, exist := downloads[src] + _, exist := downloads[src] if exist { return } @@ -166,7 +166,7 @@ func (h *HtmlToEpub) saveImages(doc *goquery.Document) map[string]string { return } _ = os.MkdirAll(h.ImagesDir, 0766) - localFile = filepath.Join(h.ImagesDir, fmt.Sprintf("%s%s", MD5str(src), filepath.Ext(uri.Path))) + localFile := filepath.Join(h.ImagesDir, fmt.Sprintf("%s%s", MD5str(src), filepath.Ext(uri.Path))) tasks.Add(src, localFile) downloads[src] = localFile @@ -197,7 +197,7 @@ func (h *HtmlToEpub) getFontURLs(html HtmlContent) (downloads map[string]string, return } - localFile, exist := downloads[src] + _, exist := downloads[src] if exist { return } @@ -208,7 +208,7 @@ func (h *HtmlToEpub) getFontURLs(html HtmlContent) (downloads map[string]string, return } _ = os.MkdirAll(h.FontsDir, 0766) - localFile = filepath.Join(h.FontsDir, fmt.Sprintf("%s%s", MD5str(src), filepath.Ext(uri.Path))) + localFile := filepath.Join(h.FontsDir, fmt.Sprintf("%s%s", MD5str(src), filepath.Ext(uri.Path))) downloads[src] = localFile }) diff --git a/utils/qrcode.go b/utils/qrcode.go index 77c77ef8..515fdfd7 100644 --- a/utils/qrcode.go +++ b/utils/qrcode.go @@ -113,16 +113,14 @@ func New() *qrcodeTerminal { func (v *qrcodeTerminal) getQRCodeString(data [][]bool) (result *QRCodeString) { str := "" + lc := len(data) for ir, row := range data { lr := len(row) - if ir == 0 || ir == 1 || ir == 2 || - ir == lr-1 || ir == lr-2 || ir == lr-3 { + if ir <= 2 || ir >= lr-3 { continue } for ic, col := range row { - lc := len(data) - if ic == 0 || ic == 1 || ic == 2 || - ic == lc-1 || ic == lc-2 || ic == lc-3 { + if ic <= 2 || ic >= lc-3 { continue } if col {