Skip to content

Commit

Permalink
feat: --authorid 参数 仅保存某一用户发言层
Browse files Browse the repository at this point in the history
close #81
  • Loading branch information
ludoux committed Mar 2, 2024
1 parent 78fecfa commit b70d6ef
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 55 deletions.
35 changes: 19 additions & 16 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,20 @@ package main
import (
"encoding/json"
"fmt"
"log"
"os"
"strings"
"time"

"github.com/imroc/req/v3"
"github.com/jessevdk/go-flags"
"github.com/ludoux/ngapost2md/config"
"github.com/ludoux/ngapost2md/nga"
"github.com/spf13/cast"
"log"
"os"
"strings"
"time"
)

type Option struct {
AuthorId int `long:"authorid" default:"0" description:"只下载此 authorid 的发言层"`
Version bool `short:"v" long:"version" description:"显示版本信息并退出"`
Help bool `short:"h" long:"help" description:"显示此帮助信息并退出"`
GenConfigFile bool `long:"gen-config-file" description:"生成默认配置文件于 config.ini 并退出"`
Expand Down Expand Up @@ -66,9 +68,10 @@ func main() {
log.Println("导出默认配置文件 config.ini 成功。")
os.Exit(0)
} else if opts.Help {
fmt.Println("使用: ngapost2md tid")
fmt.Println("使用: ngapost2md tid [--authorid aid]")
fmt.Println("选项与参数说明: ")
fmt.Println("tid: 待下载的帖子 tid 号")
fmt.Println("aid: 只看某用户 id 发言层,需配合 --authorid 参数")
fmt.Println("")
fmt.Println("ngapost2md -v, --version ", parser.FindOptionByLongName("version").Description)
fmt.Println("ngapost2md -h, --help ", parser.FindOptionByLongName("help").Description)
Expand Down Expand Up @@ -115,25 +118,25 @@ func main() {
nga.BASE_URL = cfg.Section("network").Key("base_url").String()
nga.UA = cfg.Section("network").Key("ua").String()
//默认线程数为2,仅支持1~3
nga.THREAD_COUNT = cfg.Section("network").Key("thread").InInt(2, []int{1, 2, 3})
nga.PAGE_DOWNLOAD_LIMIT = cfg.Section("network").Key("page_download_limit").RangeInt(100, -1, 100)
nga.GET_IP_LOCATION = cfg.Section("post").Key("get_ip_location").MustBool()
nga.ENHANCE_ORI_REPLY = cfg.Section("post").Key("enhance_ori_reply").MustBool()
nga.USE_LOCAL_SMILE_PIC = cfg.Section("post").Key("use_local_smile_pic").MustBool()
nga.LOCAL_SMILE_PIC_PATH = cfg.Section("post").Key("local_smile_pic_path").String()
nga.USE_TITLE_AS_FOLDER_NAME = cfg.Section("post").Key("use_title_as_folder_name").MustBool()
nga.USE_TITLE_AS_MD_FILE_NAME = cfg.Section("post").Key("use_title_as_md_file_name").MustBool()
nga.CFGFILE_THREAD_COUNT = cfg.Section("network").Key("thread").InInt(2, []int{1, 2, 3})
nga.CFGFILE_PAGE_DOWNLOAD_LIMIT = cfg.Section("network").Key("page_download_limit").RangeInt(100, -1, 100)
nga.CFGFILE_GET_IP_LOCATION = cfg.Section("post").Key("get_ip_location").MustBool()
nga.CFGFILE_ENHANCE_ORI_REPLY = cfg.Section("post").Key("enhance_ori_reply").MustBool()
nga.CFGFILE_USE_LOCAL_SMILE_PIC = cfg.Section("post").Key("use_local_smile_pic").MustBool()
nga.CFGFILE_LOCAL_SMILE_PIC_PATH = cfg.Section("post").Key("local_smile_pic_path").String()
nga.CFGFILE_USE_TITLE_AS_FOLDER_NAME = cfg.Section("post").Key("use_title_as_folder_name").MustBool()
nga.CFGFILE_USE_TITLE_AS_MD_FILE_NAME = cfg.Section("post").Key("use_title_as_md_file_name").MustBool()
nga.Client = nga.NewNgaClient()

tie := nga.Tiezi{}

path := nga.FindFolderNameByTid(tid)
path := nga.FindFolderNameByTid(tid, opts.AuthorId)
if path != "" {
log.Printf("本地存在此 tid (%s) 文件夹,追加最新更改。", path)
tie.InitFromLocal(tid)
tie.InitFromLocal(tid, opts.AuthorId)

} else {
tie.InitFromWeb(tid)
tie.InitFromWeb(tid, opts.AuthorId)
}

tie.Download()
Expand Down
92 changes: 58 additions & 34 deletions nga/nga.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,22 @@ import (
"time"

"github.com/buger/jsonparser"
"github.com/imroc/req/v3"
"github.com/panjf2000/ants/v2"
"github.com/spf13/cast"
"gopkg.in/ini.v1"
)

// 这里是配置文件可以改的
var (
THREAD_COUNT = 2
GET_IP_LOCATION = false // 获取ip地址
ENHANCE_ORI_REPLY = false // 功能见 #35
PAGE_DOWNLOAD_LIMIT = 100 // 限制单次下载的页数 #56
USE_TITLE_AS_FOLDER_NAME = false
USE_TITLE_AS_MD_FILE_NAME = false
USE_LOCAL_SMILE_PIC = false // 使用本地表情 #58
LOCAL_SMILE_PIC_PATH = "../smile/" //本地表情路径 #58
CFGFILE_THREAD_COUNT = 2
CFGFILE_GET_IP_LOCATION = false // 获取ip地址
CFGFILE_ENHANCE_ORI_REPLY = false // 功能见 #35
CFGFILE_PAGE_DOWNLOAD_LIMIT = 100 // 限制单次下载的页数 #56
CFGFILE_USE_TITLE_AS_FOLDER_NAME = false
CFGFILE_USE_TITLE_AS_MD_FILE_NAME = false
CFGFILE_USE_LOCAL_SMILE_PIC = false // 使用本地表情 #58
CFGFILE_LOCAL_SMILE_PIC_PATH = "../smile/" //本地表情路径 #58

)

Expand Down Expand Up @@ -74,6 +75,7 @@ type Floor struct {
type Floors []Floor
type Tiezi struct {
Tid int
AuthorId int //这个是用户传入的希望仅下载某用户id的发言贴参数
Title string
TitleFolderSafe string
Catelogy string
Expand Down Expand Up @@ -157,10 +159,20 @@ func (it *Floors) analyze(resp []byte, isComments bool) {
* @return {*}
*/
func (tiezi *Tiezi) page(page int) {
resp, err := Client.R().SetFormData(map[string]string{
"page": cast.ToString(page),
"tid": cast.ToString(tiezi.Tid),
}).Post("app_api.php?__lib=post&__act=list")
var resp *req.Response
var err error
if tiezi.AuthorId > 0 {
resp, err = Client.R().SetFormData(map[string]string{
"page": cast.ToString(page),
"tid": cast.ToString(tiezi.Tid),
"authorid": cast.ToString(tiezi.AuthorId),
}).Post("app_api.php?__lib=post&__act=list")
} else {
resp, err = Client.R().SetFormData(map[string]string{
"page": cast.ToString(page),
"tid": cast.ToString(tiezi.Tid),
}).Post("app_api.php?__lib=post&__act=list")
}
if err != nil {
log.Println(err.Error())
}
Expand Down Expand Up @@ -190,8 +202,8 @@ func (tiezi *Tiezi) page(page int) {
//总页数
value_int, _ = jsonparser.GetInt(resp.Bytes(), "totalPage")
tiezi.WebMaxPage = cast.ToInt(value_int)
if PAGE_DOWNLOAD_LIMIT > 0 && tiezi.WebMaxPage > (tiezi.LocalMaxPage+PAGE_DOWNLOAD_LIMIT) {
tiezi.WebMaxPage = tiezi.LocalMaxPage + PAGE_DOWNLOAD_LIMIT
if CFGFILE_PAGE_DOWNLOAD_LIMIT > 0 && tiezi.WebMaxPage > (tiezi.LocalMaxPage+CFGFILE_PAGE_DOWNLOAD_LIMIT) {
tiezi.WebMaxPage = tiezi.LocalMaxPage + CFGFILE_PAGE_DOWNLOAD_LIMIT
page_download_limit_triggered = true
}

Expand Down Expand Up @@ -220,8 +232,8 @@ func (tiezi *Tiezi) page(page int) {
* @param {int} tid 帖子tid
* @return {*}
*/
func (tiezi *Tiezi) InitFromWeb(tid int) {
tiezi.init(tid)
func (tiezi *Tiezi) InitFromWeb(tid int, authorId int) {
tiezi.init(tid, authorId)
tiezi.Version = VERSION
tiezi.Assets = map[string]string{}
tiezi.LocalMaxPage = 1
Expand All @@ -235,16 +247,16 @@ func (tiezi *Tiezi) InitFromWeb(tid int) {
* @param {int} tid 帖子tid
* @return {*}
*/
func (tiezi *Tiezi) InitFromLocal(tid int) {
tiezi.init(tid)
func (tiezi *Tiezi) InitFromLocal(tid int, authorId int) {
tiezi.init(tid, authorId)
tiezi.Version = VERSION

checkFileExistence := func(fileName string) {
if _, err := os.Stat(fileName); os.IsNotExist(err) {
log.Fatalln(fileName, "文件丢失,软件将退出。")
}
}
folderName := FindFolderNameByTid(tid)
folderName := FindFolderNameByTid(tid, authorId)
if folderName == "" {
log.Fatalln("找不到本地 tid 文件夹,软件将退出。")
}
Expand All @@ -268,13 +280,13 @@ func (tiezi *Tiezi) InitFromLocal(tid int) {
}

/**
* @description: 初始化 Tiezi。主要是创建文件夹
* @description: 初始化 Tiezi。
* @param {int} tid 帖子tid
* @param {bool} crateDict 是否创建文件夹
* @return {*}
*/
func (tiezi *Tiezi) init(tid int) {
func (tiezi *Tiezi) init(tid int, authorId int) {
tiezi.Tid = tid
tiezi.AuthorId = authorId
}

/**
Expand Down Expand Up @@ -311,7 +323,7 @@ func (tiezi *Tiezi) fixContent(floor_i int) {
//循环尾部有判断是否有comments且是否进去的操作,请注意
for {
//假如要获取IP位置则在此处获取
if GET_IP_LOCATION {
if CFGFILE_GET_IP_LOCATION {
resp, err := Client.R().SetFormData(map[string]string{
"uid": cast.ToString(floor.UserId),
}).Post("nuke.php?__lib=ucp&__act=get&__output=8")
Expand Down Expand Up @@ -394,7 +406,7 @@ func (tiezi *Tiezi) fixContent(floor_i int) {
//表情
re = regexp.MustCompile(`\[s\:.+?\:.+?\]`)
for _, it := range re.FindAllString(cont, -1) {
if !USE_LOCAL_SMILE_PIC {
if !CFGFILE_USE_LOCAL_SMILE_PIC {
cont = strings.ReplaceAll(cont, it, `![`+strings.Split(it, `:`)[2]+`(https://img4.nga.178.com/ngabbs/post/smile/`+strings.ReplaceAll(getSmile(it), `"`, ``)+`)`)
} else {
smile_name := strings.Split(it, `:`)[1] + strings.TrimRight(strings.Split(it, `:`)[2], "]")
Expand All @@ -403,7 +415,7 @@ func (tiezi *Tiezi) fixContent(floor_i int) {
} else {
smile_name = smile_name + ".png"
}
prefix := LOCAL_SMILE_PIC_PATH
prefix := CFGFILE_LOCAL_SMILE_PIC_PATH
if !strings.HasSuffix(prefix, "/") {
prefix = prefix + "/"
}
Expand Down Expand Up @@ -518,7 +530,7 @@ func (tiezi *Tiezi) fixContent(floor_i int) {
quoteAuthor = anony(quoteAuthor)
}
replyedText := ":"
if ENHANCE_ORI_REPLY {
if CFGFILE_ENHANCE_ORI_REPLY {
replyedFloor := tiezi.findFloorByPid(cast.ToInt(quotePid))
if replyedFloor != nil {
replyedText = "说:\n>" + strings.ReplaceAll(replyedFloor.Content, "\n", "\n>")
Expand Down Expand Up @@ -550,7 +562,7 @@ func (tiezi *Tiezi) fixContent(floor_i int) {
func (tiezi *Tiezi) fixFloorContent(startFloor_i int) {

var wg sync.WaitGroup
p, _ := ants.NewPoolWithFunc(THREAD_COUNT, func(floor_i interface{}) {
p, _ := ants.NewPoolWithFunc(CFGFILE_THREAD_COUNT, func(floor_i interface{}) {
if tiezi.Floors[cast.ToInt(floor_i)].Lou != -1 {
responseChannel <- fmt.Sprintf("开始修正第 %02d 楼层", cast.ToInt(floor_i))
tiezi.fixContent(cast.ToInt(floor_i))
Expand Down Expand Up @@ -588,7 +600,7 @@ func (tiezi *Tiezi) genMarkdown(localMaxFloor int) {
mdFilePath := filepath.Join(folder, "post.md")
if _, err := os.Stat(mdFilePath); os.IsNotExist(err) {
//post.md不存在,判断是否需要个性化
if USE_TITLE_AS_MD_FILE_NAME {
if CFGFILE_USE_TITLE_AS_MD_FILE_NAME {
mdName := fmt.Sprintf("%s.md", tiezi.TitleFolderSafe)
mdFilePath = filepath.Join(folder, mdName)
}
Expand All @@ -614,7 +626,11 @@ func (tiezi *Tiezi) genMarkdown(localMaxFloor int) {
}

if floor.Pid == 0 {
_, _ = f.WriteString(fmt.Sprintf("### %s\n\nMade by ngapost2md (c) ludoux [GitHub Repo](https://github.com/ludoux/ngapost2md)\n\n", tiezi.Title))
var authorIdOptText = ""
if tiezi.AuthorId > 0 {
authorIdOptText = fmt.Sprintf("-只看 %d", tiezi.AuthorId)
}
_, _ = f.WriteString(fmt.Sprintf("### %s%s\n\nMade by ngapost2md (c) ludoux [GitHub Repo](https://github.com/ludoux/ngapost2md)\n\n", tiezi.Title, authorIdOptText))
}

if floor.Pid == 0 && len(tiezi.HotPosts) > 0 {
Expand Down Expand Up @@ -685,14 +701,22 @@ func responseController() {

// 会首先调用FindFolderNameByTid,确定本地没有相关文件夹再返回指定格式文件名。否则返回本地已有文件名
func (tiezi *Tiezi) GetNeededFolderName() string {
already := FindFolderNameByTid(tiezi.Tid)
already := FindFolderNameByTid(tiezi.Tid, tiezi.AuthorId)
if already != "" {
return already
}
if USE_TITLE_AS_FOLDER_NAME {
return fmt.Sprintf("%d-%s", tiezi.Tid, tiezi.TitleFolderSafe)
if CFGFILE_USE_TITLE_AS_FOLDER_NAME {
if tiezi.AuthorId > 0 {
return fmt.Sprintf("%d(%d)-%s", tiezi.Tid, tiezi.AuthorId, tiezi.TitleFolderSafe)
} else {
return fmt.Sprintf("%d-%s", tiezi.Tid, tiezi.TitleFolderSafe)
}
} else {
return cast.ToString(tiezi.Tid)
if tiezi.AuthorId > 0 {
return fmt.Sprintf("%d(%d)", tiezi.Tid, tiezi.AuthorId)
} else {
return cast.ToString(tiezi.Tid)
}
}
}

Expand Down Expand Up @@ -726,7 +750,7 @@ func (tiezi *Tiezi) SaveAssetsMap() {
func (tiezi *Tiezi) Download() {
if tiezi.Tid != 0 {
var wg sync.WaitGroup
p, _ := ants.NewPoolWithFunc(THREAD_COUNT, func(page interface{}) {
p, _ := ants.NewPoolWithFunc(CFGFILE_THREAD_COUNT, func(page interface{}) {
time.Sleep(time.Millisecond * time.Duration(DELAY_MS))
responseChannel <- fmt.Sprintf("下载第 %02d 页", page)
//1. 并行下载page
Expand Down
22 changes: 17 additions & 5 deletions nga/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,23 +78,35 @@ func ToSaveFilename(in string) string {
}

// 找不到时会直接返回 ""
func FindFolderNameByTid(tid int) string {
fi, err := os.Stat(cast.ToString(tid))
func FindFolderNameByTid(tid int, authorId int) string {
var folderName string
if authorId > 0 {
folderName = fmt.Sprintf("%d(%d)", tid, authorId)
} else {
folderName = cast.ToString(tid)
}
fi, err := os.Stat(folderName)
if err == nil && fi.IsDir() {
return cast.ToString(tid)
return folderName
} else if err != nil && !os.IsNotExist(err) {
log.Fatalln(err.Error())
return ""
}
//即不存在直接以 tid 命名的文件夹,接下来判断是否存在以 tid- 开头的文件夹
matches, err := filepath.Glob(fmt.Sprintf("./%d-*", tid))
if authorId > 0 {
folderName = fmt.Sprintf("./%d(%d)-*", tid, authorId)
} else {
folderName = fmt.Sprintf("./%d-*", tid)
}
matches, err := filepath.Glob(folderName)
if err != nil {
log.Fatalln(err.Error())
return ""
}
if len(matches) == 1 {
return matches[0]
} else if len(matches) > 1 {
log.Fatalln("有多个文件夹匹配:", fmt.Sprintf("./%d-*", tid))
log.Fatalln("有多个文件夹匹配:", folderName)
return ""
}
return ""
Expand Down

0 comments on commit b70d6ef

Please sign in to comment.