add comment

This commit is contained in:
niuhuan 2021-10-19 18:26:12 +08:00
parent 6dc77199de
commit 4e838a2c45
8 changed files with 79 additions and 8 deletions

View File

@ -9,7 +9,7 @@ import (
"pgo/pikapi/utils" "pgo/pikapi/utils"
) )
// InitApplication 初始化文件保存的位置 // InitApplication 由不同的平台直接调用, 根据提供的路径初始化数据库, 资料文件夹
func InitApplication(applicationDir string) { func InitApplication(applicationDir string) {
println("初始化 : " + applicationDir) println("初始化 : " + applicationDir)
var databasesDir, remoteDir, downloadDir, tmpDir string var databasesDir, remoteDir, downloadDir, tmpDir string

View File

@ -1,7 +1,8 @@
// 透传Client的功能并增加缓存
package controller package controller
import ( import (
"context"
"encoding/json" "encoding/json"
"fmt" "fmt"
source "github.com/niuhuan/pica-go" source "github.com/niuhuan/pica-go"
@ -12,9 +13,13 @@ import (
"pgo/pikapi/database/network_cache" "pgo/pikapi/database/network_cache"
"pgo/pikapi/database/properties" "pgo/pikapi/database/properties"
"regexp" "regexp"
"time"
)
import (
"context"
"strconv" "strconv"
"strings" "strings"
"time"
) )
func InitClient() { func InitClient() {
@ -405,7 +410,7 @@ func postComment(params string) (string, error) {
func postChildComment(params string) (string, error) { func postChildComment(params string) (string, error) {
var paramsStruct struct { var paramsStruct struct {
ComicId string `json:"comicId"` ComicId string `json:"comicId"`
CommentId string `json:"commentId"` CommentId string `json:"commentId"`
Content string `json:"content"` Content string `json:"content"`
} }

View File

@ -36,6 +36,7 @@ func notifyExport(str string) {
onEvent("EXPORT", str) onEvent("EXPORT", str)
} }
// 将interface序列化成字符串, 方便与flutter通信
func serialize(point interface{}, err error) (string, error) { func serialize(point interface{}, err error) (string, error) {
if err != nil { if err != nil {
return "", err return "", err

View File

@ -11,6 +11,10 @@ import (
"time" "time"
) )
// 使用协程进行后台下载
// downloadRunning 如果为false则停止下载
// downloadRestart 为true则取消从新启动下载功能
var downloadRunning = false var downloadRunning = false
var downloadRestart = false var downloadRestart = false
@ -18,16 +22,24 @@ var downloadingComic *comic_center.ComicDownload
var downloadingEp *comic_center.ComicDownloadEp var downloadingEp *comic_center.ComicDownloadEp
var downloadingPicture *comic_center.ComicDownloadPicture var downloadingPicture *comic_center.ComicDownloadPicture
var dlFlag = true
// 程序启动后仅调用一次, 启动后台线程
func downloadBackground() { func downloadBackground() {
println("后台线程启动") println("后台线程启动")
go downloadBegin() if dlFlag {
dlFlag = false
go downloadBegin()
}
} }
// 下载启动/重新启动会暂停三秒
func downloadBegin() { func downloadBegin() {
time.Sleep(time.Second * 3) time.Sleep(time.Second * 3)
go downloadLoadComic() go downloadLoadComic()
} }
// 下载周期中, 每个下载单元会调用此方法, 如果返回true应该停止当前动作
func downloadHasStop() bool { func downloadHasStop() bool {
if !downloadRunning { if !downloadRunning {
go downloadBegin() go downloadBegin()
@ -41,6 +53,7 @@ func downloadHasStop() bool {
return false return false
} }
// 删除下载任务, 当用户要删除下载的时候, 他会被加入删除队列, 而不是直接被删除, 以减少出错
func downloadDelete() bool { func downloadDelete() bool {
c, e := comic_center.DeletingComic() c, e := comic_center.DeletingComic()
if e != nil { if e != nil {
@ -57,39 +70,50 @@ func downloadDelete() bool {
return false return false
} }
// 加载第一个需要下载的漫画
func downloadLoadComic() { func downloadLoadComic() {
// 每次下载完一个漫画, 或者启动的时候, 首先进行删除任务
for downloadDelete() { for downloadDelete() {
} }
// 检测是否需要停止
if downloadHasStop() { if downloadHasStop() {
return return
} }
// 找到第一个要下载的漫画, 查库有错误就停止, 因为这些错误很少出现, 一旦出现必然是严重的, 例如数据库文件突然被删除
var err error var err error
downloadingComic, err = comic_center.LoadFirstNeedDownload() downloadingComic, err = comic_center.LoadFirstNeedDownload()
// 查库有错误就停止
if err != nil { if err != nil {
panic(err) panic(err)
} }
// 处理找到的下载任务
go downloadInitComic() go downloadInitComic()
} }
// 初始化找到的下载任务
func downloadInitComic() { func downloadInitComic() {
// 检测是否需要停止
if downloadHasStop() { if downloadHasStop() {
return return
} }
// 若没有漫画要下载则重新启动
if downloadingComic == nil { if downloadingComic == nil {
println("没有找到要下载的漫画") println("没有找到要下载的漫画")
go downloadBegin() go downloadBegin()
return return
} }
// 打印日志, 并向前端的eventChannel发送下载信息
println("正在下载漫画 " + downloadingComic.Title) println("正在下载漫画 " + downloadingComic.Title)
downloadComicEventSend(downloadingComic) downloadComicEventSend(downloadingComic)
eps, err := comic_center.ListDownloadEpByComicId(downloadingComic.ID) eps, err := comic_center.ListDownloadEpByComicId(downloadingComic.ID)
if err != nil { if err != nil {
panic(err) panic(err)
} }
// 找到这个漫画需要下载的EP, 并搜索获取图片地址
for _, ep := range eps { for _, ep := range eps {
// FetchedPictures字段标志着这个章节的图片地址有没有获取过, 如果没有获取过就重新获取
if !ep.FetchedPictures { if !ep.FetchedPictures {
println("正在获取章节的图片 " + downloadingComic.Title + " " + ep.Title) println("正在获取章节的图片 " + downloadingComic.Title + " " + ep.Title)
// 搜索图片地址, 如果五次没有请求成功, 就不在请求
for i := 0; i < 5; i++ { for i := 0; i < 5; i++ {
if client.Token == "" { if client.Token == "" {
continue continue
@ -102,6 +126,7 @@ func downloadInitComic() {
ep.FetchedPictures = true ep.FetchedPictures = true
break break
} }
// 如果未能获取图片地址, 则直接置为失败
if !ep.FetchedPictures { if !ep.FetchedPictures {
println("章节的图片获取失败 " + downloadingComic.Title + " " + ep.Title) println("章节的图片获取失败 " + downloadingComic.Title + " " + ep.Title)
err = comic_center.EpFailed(ep.ID) err = comic_center.EpFailed(ep.ID)
@ -115,11 +140,14 @@ func downloadInitComic() {
} }
} }
} }
// 获取图片地址结束, 去初始化下载的章节
go downloadLoadEp() go downloadLoadEp()
} }
// 获取图片地址
func downloadFetchPictures(downloadEp *comic_center.ComicDownloadEp) error { func downloadFetchPictures(downloadEp *comic_center.ComicDownloadEp) error {
var list []comic_center.ComicDownloadPicture var list []comic_center.ComicDownloadPicture
// 官方的图片只能分页获取, 从第1页开始获取, 每页最多40张图片
page := 1 page := 1
for true { for true {
rsp, err := client.ComicPicturePage(downloadingComic.ID, int(downloadEp.EpOrder), page) rsp, err := client.ComicPicturePage(downloadingComic.ID, int(downloadEp.EpOrder), page)
@ -137,12 +165,14 @@ func downloadFetchPictures(downloadEp *comic_center.ComicDownloadEp) error {
Path: doc.Media.Path, Path: doc.Media.Path,
}) })
} }
// 如果不是最后一页, 页码加1, 获取下一页
if rsp.Page.Page < rsp.Page.Pages { if rsp.Page.Page < rsp.Page.Pages {
page++ page++
continue continue
} }
break break
} }
// 保存获取到的图片
err := comic_center.FetchPictures(downloadEp.ComicId, downloadEp.ID, &list) err := comic_center.FetchPictures(downloadEp.ComicId, downloadEp.ID, &list)
if err != nil { if err != nil {
panic(err) panic(err)
@ -151,10 +181,13 @@ func downloadFetchPictures(downloadEp *comic_center.ComicDownloadEp) error {
return err return err
} }
// 初始化下载
func downloadLoadEp() { func downloadLoadEp() {
// 周期停止检测
if downloadHasStop() { if downloadHasStop() {
return return
} }
// 找到第一个需要下载的章节并去处理 (未下载失败的, 且未完成下载的)
var err error var err error
downloadingEp, err = comic_center.LoadFirstNeedDownloadEp(downloadingComic.ID) downloadingEp, err = comic_center.LoadFirstNeedDownloadEp(downloadingComic.ID)
if err != nil { if err != nil {
@ -163,29 +196,36 @@ func downloadLoadEp() {
go downloadInitEp() go downloadInitEp()
} }
// 处理需要下载的EP
func downloadInitEp() { func downloadInitEp() {
if downloadingEp == nil { if downloadingEp == nil {
// 所有Ep都下完了, 汇总Download下载情况 // 所有Ep都下完了, 汇总Download下载情况
go downloadSummaryDownload() go downloadSummaryDownload()
return return
} }
// 没有下载完则去下载图片
println("正在下载章节 " + downloadingEp.Title) println("正在下载章节 " + downloadingEp.Title)
go downloadLoadPicture() go downloadLoadPicture()
} }
// EP下载汇总
func downloadSummaryDownload() { func downloadSummaryDownload() {
// 暂停检测
if downloadHasStop() { if downloadHasStop() {
return return
} }
// 加载这个漫画的所有EP
list, err := comic_center.ListDownloadEpByComicId(downloadingComic.ID) list, err := comic_center.ListDownloadEpByComicId(downloadingComic.ID)
if err != nil { if err != nil {
panic(err) panic(err)
} }
// 判断所有章节是否下载完成
over := true over := true
for _, downloadEp := range list { for _, downloadEp := range list {
over = over && downloadEp.DownloadFinished over = over && downloadEp.DownloadFinished
} }
if over { if over {
// 如果所有章节下载完成则下载成功
err = comic_center.DownloadSuccess(downloadingComic.ID) err = comic_center.DownloadSuccess(downloadingComic.ID)
if err != nil { if err != nil {
panic(err) panic(err)
@ -193,17 +233,22 @@ func downloadSummaryDownload() {
downloadingComic.DownloadFinished = true downloadingComic.DownloadFinished = true
downloadingComic.DownloadFinishedTime = time.Now() downloadingComic.DownloadFinishedTime = time.Now()
} else { } else {
// 否则下载失败
err = comic_center.DownloadFailed(downloadingComic.ID) err = comic_center.DownloadFailed(downloadingComic.ID)
if err != nil { if err != nil {
panic(err) panic(err)
} }
downloadingComic.DownloadFailed = true downloadingComic.DownloadFailed = true
} }
// 向前端发送下载状态
downloadComicEventSend(downloadingComic) downloadComicEventSend(downloadingComic)
// 去下载下一个漫画
go downloadLoadComic() go downloadLoadComic()
} }
// 加载需要下载的图片
func downloadLoadPicture() { func downloadLoadPicture() {
// 暂停检测
if downloadHasStop() { if downloadHasStop() {
return return
} }
@ -216,6 +261,7 @@ func downloadLoadPicture() {
} }
func downloadInitPicture() { func downloadInitPicture() {
// 暂停检测
if downloadHasStop() { if downloadHasStop() {
return return
} }
@ -224,42 +270,50 @@ func downloadInitPicture() {
go downloadSummaryEp() go downloadSummaryEp()
return return
} }
// 下载图片, 最多重试5次
println("正在下载图片 " + fmt.Sprintf("%d", downloadingPicture.RankInEp)) println("正在下载图片 " + fmt.Sprintf("%d", downloadingPicture.RankInEp))
for i := 0; i < 5; i++ { for i := 0; i < 5; i++ {
err := downloadThePicture(downloadingPicture) err := downloadThePicture(downloadingPicture)
if err != nil { if err != nil {
continue continue
} }
// 对下载的漫画临时变量热更新并通知前端
downloadingPicture.DownloadFinished = true downloadingPicture.DownloadFinished = true
downloadingEp.DownloadPictureCount = downloadingEp.DownloadPictureCount + 1 downloadingEp.DownloadPictureCount = downloadingEp.DownloadPictureCount + 1
downloadingComic.DownloadPictureCount = downloadingComic.DownloadPictureCount + 1 downloadingComic.DownloadPictureCount = downloadingComic.DownloadPictureCount + 1
downloadComicEventSend(downloadingComic) downloadComicEventSend(downloadingComic)
break break
} }
// 没能下载成功, 图片置为下载失败
if !downloadingPicture.DownloadFinished { if !downloadingPicture.DownloadFinished {
err := comic_center.PictureFailed(downloadingPicture.ID) err := comic_center.PictureFailed(downloadingPicture.ID)
if err != nil { if err != nil {
panic(err) panic(err)
} }
} }
// 加载下一张需要下载的图片
go downloadLoadPicture() go downloadLoadPicture()
} }
// 下载指定图片
func downloadThePicture(picturePoint *comic_center.ComicDownloadPicture) error { func downloadThePicture(picturePoint *comic_center.ComicDownloadPicture) error {
// 为了不和页面前端浏览的数据冲突, 使用url做hash锁
lock := utils2.HashLock(fmt.Sprintf("%s$%s", picturePoint.FileServer, picturePoint.Path)) lock := utils2.HashLock(fmt.Sprintf("%s$%s", picturePoint.FileServer, picturePoint.Path))
lock.Lock() lock.Lock()
defer lock.Unlock() defer lock.Unlock()
// 图片保存位置使用相对路径储存, 使用绝对路径操作
picturePath := fmt.Sprintf("%s/%d/%d", picturePoint.ComicId, picturePoint.EpOrder, picturePoint.RankInEp) picturePath := fmt.Sprintf("%s/%d/%d", picturePoint.ComicId, picturePoint.EpOrder, picturePoint.RankInEp)
realPath := downloadPath(picturePath) realPath := downloadPath(picturePath)
// 从缓存 // 从缓存获取图片
buff, img, format, err := decodeFromCache(picturePoint.FileServer, picturePoint.Path) buff, img, format, err := decodeFromCache(picturePoint.FileServer, picturePoint.Path)
if err != nil { if err != nil {
// 从网络 // 若缓存不存在, 则从网络获取
buff, img, format, err = decodeFromUrl(picturePoint.FileServer, picturePoint.Path) buff, img, format, err = decodeFromUrl(picturePoint.FileServer, picturePoint.Path)
} }
if err != nil { if err != nil {
return err return err
} }
// 将图片保存到文件
dir := filepath.Dir(realPath) dir := filepath.Dir(realPath)
if _, err := os.Stat(dir); os.IsNotExist(err) { if _, err := os.Stat(dir); os.IsNotExist(err) {
os.Mkdir(dir, const_value.CreateDirMode) os.Mkdir(dir, const_value.CreateDirMode)
@ -268,6 +322,7 @@ func downloadThePicture(picturePoint *comic_center.ComicDownloadPicture) error {
if err != nil { if err != nil {
return err return err
} }
// 存入数据库
return comic_center.PictureSuccess( return comic_center.PictureSuccess(
picturePoint.ComicId, picturePoint.ComicId,
picturePoint.EpId, picturePoint.EpId,
@ -280,14 +335,18 @@ func downloadThePicture(picturePoint *comic_center.ComicDownloadPicture) error {
) )
} }
// EP 下载内容汇总
func downloadSummaryEp() { func downloadSummaryEp() {
// 暂停检测
if downloadHasStop() { if downloadHasStop() {
return return
} }
// 找到所有下载的图片
list, err := comic_center.ListDownloadPictureByEpId(downloadingEp.ID) list, err := comic_center.ListDownloadPictureByEpId(downloadingEp.ID)
if err != nil { if err != nil {
panic(err) panic(err)
} }
// 全部下载完成置为成功, 否则置为失败
over := true over := true
for _, downloadPicture := range list { for _, downloadPicture := range list {
over = over && downloadPicture.DownloadFinished over = over && downloadPicture.DownloadFinished
@ -303,5 +362,6 @@ func downloadSummaryEp() {
panic(err) panic(err)
} }
} }
// 去加载下一个EP
go downloadLoadEp() go downloadLoadEp()
} }

View File

@ -5,6 +5,7 @@ import (
"strings" "strings"
) )
// 获取IP的集合
func clientIpSet() (string, error) { func clientIpSet() (string, error) {
address, err := net.InterfaceAddrs() address, err := net.InterfaceAddrs()
if err != nil { if err != nil {

View File

@ -2,6 +2,7 @@ package controller
import "pgo/pikapi/database/comic_center" import "pgo/pikapi/database/comic_center"
// 根据comicId获得标题但是必须是下载的内容(暂未使用)
func specialDownloadTitle(comicId string) (string, error) { func specialDownloadTitle(comicId string) (string, error) {
info, err := comic_center.DownloadInfo(comicId) info, err := comic_center.DownloadInfo(comicId)
if err != nil { if err != nil {

View File

@ -113,6 +113,8 @@ func ViewComicUpdateInfo(view *ComicView) error {
} }
func ViewComic(comicId string) error { func ViewComic(comicId string) error {
mutex.Lock()
defer mutex.Unlock()
return db.Model(&ComicView{}).Where( return db.Model(&ComicView{}).Where(
"id = ?", comicId, "id = ?", comicId,
).Update( ).Update(

View File

@ -2,6 +2,7 @@ package utils
import "time" import "time"
// Timestamp 获取当前的Unix时间戳
func Timestamp() int64 { func Timestamp() int64 {
return time.Now().UnixNano() / int64(time.Millisecond) return time.Now().UnixNano() / int64(time.Millisecond)
} }