From c61cc0dd3f5f3b2d71279313677494ee2d35797b Mon Sep 17 00:00:00 2001 From: jackyzy823 Date: Sat, 21 Sep 2024 23:36:05 +0800 Subject: [PATCH 1/4] Implement novel comments --- assets/css/style.css | 60 +++++++++++++++---------------- assets/css/style.scss | 72 ++++++++++++++++++------------------- assets/views/novel.jet.html | 31 ++++++++++++++++ core/endpoints.go | 6 ++++ core/novel.go | 22 ++++++++++++ server/routes/novel.go | 8 +++++ 6 files changed, 133 insertions(+), 66 deletions(-) diff --git a/assets/css/style.css b/assets/css/style.css index c62abaa..13d1520 100644 --- a/assets/css/style.css +++ b/assets/css/style.css @@ -832,36 +832,6 @@ edit style.scss .illust .illust-description { font-size: 0.85em; } - .illust .comment { - display: flex; - margin-bottom: 10px; - } - .illust .comment p { - margin: 0; - font-size: 0.8em; - } - .illust .comment .comment-avatar { - width: 40px; - height: 40px; - border-radius: 50%; - margin-right: 10px; - } - .illust .comment .comment-author { - color: #fff; - font-size: medium; - font-weight: bold; - } - .illust .comment .stamp { - width: 96px; - height: 96px; - border-radius: 4px; - } - .illust .comment .emoji { - width: 24px; - height: 24px; - margin-left: 3px; - margin-right: 3px; - } .illust .illust-other-works a.illust-other-works-author { display: inline-flex; align-items: center; @@ -877,6 +847,36 @@ edit style.scss object-fit: cover; object-position: center top; } + .comment { + display: flex; + margin-bottom: 10px; + } + .comment p { + margin: 0; + font-size: 0.8em; + } + .comment .comment-avatar { + width: 40px; + height: 40px; + border-radius: 50%; + margin-right: 10px; + } + .comment .comment-author { + color: #fff; + font-size: medium; + font-weight: bold; + } + .comment .stamp { + width: 96px; + height: 96px; + border-radius: 4px; + } + .comment .emoji { + width: 24px; + height: 24px; + margin-left: 3px; + margin-right: 3px; + } .novel-container { display: grid; grid-template-columns: repeat(auto-fit, minmax(407px, 1fr)); diff --git a/assets/css/style.scss b/assets/css/style.scss index 1e471a5..2a65e97 100644 --- a/assets/css/style.scss +++ b/assets/css/style.scss @@ -1111,42 +1111,6 @@ $font-fallback-sans: YuGothic, } - .comment { - display: flex; - margin-bottom: 10px; - - p { - margin: 0; - font-size: 0.8em; - } - - .comment-avatar { - width: 40px; - height: 40px; - border-radius: 50%; - margin-right: 10px; - } - - .comment-author { - color: $fg; - font-size: medium; - font-weight: bold; - } - - .stamp { - width: 96px; - height: 96px; - border-radius: 4px; - } - - .emoji { - width: 24px; - height: 24px; - margin-left: 3px; - margin-right: 3px; - } - } - .illust-other-works { a.illust-other-works-author { display: inline-flex; @@ -1167,6 +1131,42 @@ $font-fallback-sans: YuGothic, } } + .comment { + display: flex; + margin-bottom: 10px; + + p { + margin: 0; + font-size: 0.8em; + } + + .comment-avatar { + width: 40px; + height: 40px; + border-radius: 50%; + margin-right: 10px; + } + + .comment-author { + color: $fg; + font-size: medium; + font-weight: bold; + } + + .stamp { + width: 96px; + height: 96px; + border-radius: 4px; + } + + .emoji { + width: 24px; + height: 24px; + margin-left: 3px; + margin-right: 3px; + } + } + .novel-container { display: grid; diff --git a/assets/views/novel.jet.html b/assets/views/novel.jet.html index 3c15c9d..73417a5 100644 --- a/assets/views/novel.jet.html +++ b/assets/views/novel.jet.html @@ -122,6 +122,37 @@ +
+
+ Comments + {{- if .Novel.CommentOff == 1 }} +

The creator turned comments off

+ {{- else if .Novel.CommentCount == 0 }} +

There are no comments yet

+ {{- else }} {{ range .Novel.CommentsList }} +
+ + {{ .AuthorName }} + +
+ + {{- .AuthorName }} + +

+ {{- if .Stamp }} + /proxy/s.pximg.net/common/images/stamp/generated-stamps/{{ .Stamp }}_s.jpg + {{- else }} {{ raw: parseEmojis(.Context) }} {{ end }} +

+ + {{ .Date }} +
+
+ {{- end }} {{ end }} +
+ +
+

Related works

{{- range .NovelRelated }} {{- include "fragments/novel-tn" . }} diff --git a/core/endpoints.go b/core/endpoints.go index 0758b7e..3606860 100644 --- a/core/endpoints.go +++ b/core/endpoints.go @@ -141,6 +141,12 @@ func GetNovelRelatedURL(id string, limit int) string { return fmt.Sprintf(base, id, limit) } +func GetNovelCommentsURL(id string) string { + base := "https://www.pixiv.net/ajax/novels/comments/roots?novel_id=%s&offset=0&limit=100" + + return fmt.Sprintf(base, id) +} + func GetNovelSeriesURL(id string) string { base := "https://www.pixiv.net/ajax/novel/series/%s" diff --git a/core/novel.go b/core/novel.go index 07780d6..9cb2eaf 100644 --- a/core/novel.go +++ b/core/novel.go @@ -60,6 +60,7 @@ type Novel struct { ViewMode int `json:"viewMode"` // ... } `json:"suggestedSettings"` + CommentsList []Comment } type NovelBrief struct { @@ -150,3 +151,24 @@ func GetNovelRelated(r *http.Request, id string) ([]NovelBrief, error) { return novels.List, nil } + +func GetNovelComments(r *http.Request, id string) ([]Comment, error) { + var body struct { + Comments []Comment `json:"comments"` + } + + URL := GetNovelCommentsURL(id) + + response, err := API_GET_UnwrapJson(r.Context(), URL, "") + if err != nil { + return nil, err + } + response = session.ProxyImageUrl(r, response) + + err = json.Unmarshal([]byte(response), &body) + if err != nil { + return nil, err + } + + return body.Comments, nil +} diff --git a/server/routes/novel.go b/server/routes/novel.go index 3650e4a..a303ff3 100644 --- a/server/routes/novel.go +++ b/server/routes/novel.go @@ -26,6 +26,14 @@ func NovelPage(w http.ResponseWriter, r *http.Request) error { return err } + if novel.CommentOff == 0 { + // TODO should use token only if R-18/R-18G + comments, err := core.GetNovelComments(r, id) + if err == nil { + novel.CommentsList = comments + } + } + user, err := core.GetUserBasicInformation(r, novel.UserID) if err != nil { return err From 517fef6e78bcfd013af43dd09c2acad6f2ba6e34 Mon Sep 17 00:00:00 2001 From: jackyzy823 Date: Sun, 22 Sep 2024 13:46:16 +0800 Subject: [PATCH 2/4] Support special marks for novel 1. `rb` mark for furigana 2. `jumpuri` mark to open link externally 3. `chapter` mark 4. `jump` to jump to page num anchor 5. Refactor `newpage` mark --- assets/css/style.css | 4 ++++ assets/css/style.scss | 5 +++++ server/template/templateFunctions.go | 29 +++++++++++++++++++++++++++- 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/assets/css/style.css b/assets/css/style.css index 13d1520..1141254 100644 --- a/assets/css/style.css +++ b/assets/css/style.css @@ -989,6 +989,10 @@ edit style.scss max-height: 100%; margin: 0 0.5rem; } + .novel .novel-content .novel-content-text a { + text-decoration: underline; + color: black; + } .novel .novel-attr { display: flex; align-items: center; diff --git a/assets/css/style.scss b/assets/css/style.scss index 2a65e97..0be2dbc 100644 --- a/assets/css/style.scss +++ b/assets/css/style.scss @@ -1297,6 +1297,11 @@ $font-fallback-sans: YuGothic, max-height: 100%; margin: 0 0.5rem; } + + a { + text-decoration: underline; + color: black; + } } } diff --git a/server/template/templateFunctions.go b/server/template/templateFunctions.go index c92ada1..b083ad4 100644 --- a/server/template/templateFunctions.go +++ b/server/template/templateFunctions.go @@ -305,8 +305,35 @@ func GetTemplateFunctions() map[string]any { return s[:len(s)-6] }, "renderNovel": func(s string) HTML { + furiganaTemplate := `$1($2)` + furiganaPattern := regexp.MustCompile(`\[\[rb:\s*(.+?)\s*>\s*(.+?)\s*\]\]`) + s = furiganaPattern.ReplaceAllString(s, furiganaTemplate) + + chapterTemplate := `

$1

` + chapterPattern := regexp.MustCompile(`\[chapter:\s*(.+?)\s*\]`) + s = chapterPattern.ReplaceAllString(s, chapterTemplate) + + jumpUriTemplate := `$1` + jumpUriPattern := regexp.MustCompile(`\[\[jumpuri:\s*(.+?)\s*>\s*(.+?)\s*\]\]`) + s = jumpUriPattern.ReplaceAllString(s, jumpUriTemplate) + + jumpPageTemplate := `To page $1` + jumpPagePattern := regexp.MustCompile(`\[jump:\s*(\d+?)\s*\]`) + s = jumpPagePattern.ReplaceAllString(s, jumpPageTemplate) + + if strings.Contains(s, "[newpage]") { + // if [newpage] in content , then prepend
to the page + s = `
` + s + pageIdx := 1 + + // Should run before replace `\n` -> `
` + newPagePattern := regexp.MustCompile(`\s*\[newpage\]\s*`) + s = newPagePattern.ReplaceAllStringFunc(s, func(_ string) string { + pageIdx += 1 + return fmt.Sprintf(`

`, pageIdx) + }) + } s = strings.ReplaceAll(s, "\n", "
") - s = strings.ReplaceAll(s, "[newpage]", "Insert page separator here.") return HTML(s) }, "novelGenre": GetNovelGenre, From 8b978be40f8674cb1c480d6aa852550af1eee028 Mon Sep 17 00:00:00 2001 From: jackyzy823 Date: Sun, 22 Sep 2024 17:15:32 +0800 Subject: [PATCH 3/4] Make illust in novel clickable --- assets/views/fragments/artwork.jet.html | 6 +++--- core/novel.go | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/assets/views/fragments/artwork.jet.html b/assets/views/fragments/artwork.jet.html index 7bee19c..deba968 100644 --- a/assets/views/fragments/artwork.jet.html +++ b/assets/views/fragments/artwork.jet.html @@ -1,12 +1,12 @@ {{- if !.IsUgoira }}
{{- range index := .Images }} - + {{- if .Width != 0 && .Height != 0 }} {* todo: do not reflow the page because of loading image *} - Page {{ index }} + Page {{ index + 1 }} {{- else }} - Page {{ index }} + Page {{ index + 1 }} {{- end }} {{- end }} diff --git a/core/novel.go b/core/novel.go index 9cb2eaf..81e938f 100644 --- a/core/novel.go +++ b/core/novel.go @@ -3,6 +3,7 @@ package core import ( "fmt" "regexp" + "strings" "time" "net/http" @@ -124,7 +125,9 @@ func GetNovelByID(r *http.Request, id string) (Novel, error) { url := re_t.FindString(response) url = session.ProxyImageUrl(r, url[11:]) // truncate the "original": - return fmt.Sprintf(`%s`, url, s) + // make [pixivimage:illustid-index] jump to anchor + link := fmt.Sprintf("/artworks/%s", strings.ReplaceAll(illustid, "-", "#")) + return fmt.Sprintf(`%s`, link, url, s) }) return novel, nil From 0a0afa706cb99ef4bc425778e7bdb355375e939d Mon Sep 17 00:00:00 2001 From: jackyzy823 Date: Sun, 22 Sep 2024 18:28:02 +0800 Subject: [PATCH 4/4] Support uploadedimage mark in novel --- core/novel.go | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/core/novel.go b/core/novel.go index 81e938f..aeb8708 100644 --- a/core/novel.go +++ b/core/novel.go @@ -61,6 +61,17 @@ type Novel struct { ViewMode int `json:"viewMode"` // ... } `json:"suggestedSettings"` + TextEmbeddedImages map[string]struct { + NovelImageId string `json:"novelImageId"` + SanityLevel string `json:"sl"` + Urls struct { + Two40Mw string `json:"240mw"` + Four80Mw string `json:"480mw"` + One200X1200 string `json:"1200x1200"` + One28X128 string `json:"128x128"` + Original string `json:"original"` + } `json:"urls"` + } `json:"textEmbeddedImages"` CommentsList []Comment } @@ -130,6 +141,16 @@ func GetNovelByID(r *http.Request, id string) (Novel, error) { return fmt.Sprintf(`%s`, link, url, s) }) + re_u := regexp.MustCompile(`\[uploadedimage:(\d+)\]`) + re_id := regexp.MustCompile(`\d+`) + novel.Content = re_u.ReplaceAllStringFunc(novel.Content, func(s string) string { + imageId := re_id.FindString(s) + if val, ok := novel.TextEmbeddedImages[imageId]; ok { + return fmt.Sprintf(`%s`, val.Urls.Original, s) + } + return s + }) + return novel, nil }