template.go 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. package serve
  2. import (
  3. "fmt"
  4. "html/template"
  5. "math"
  6. "math/rand"
  7. "net/url"
  8. "regexp"
  9. "strings"
  10. "time"
  11. site "codeberg.org/vnpower/pixivfe/v2/core/http"
  12. core "codeberg.org/vnpower/pixivfe/v2/core/webapi"
  13. )
  14. func GetRandomColor() string {
  15. // Some color shade I stole
  16. colors := []string{
  17. // Green
  18. "#C8847E",
  19. "#C8A87E",
  20. "#C8B87E",
  21. "#C8C67E",
  22. "#C7C87E",
  23. "#C2C87E",
  24. "#BDC87E",
  25. "#82C87E",
  26. "#82C87E",
  27. "#7EC8AF",
  28. "#7EAEC8",
  29. "#7EA6C8",
  30. "#7E99C8",
  31. "#7E87C8",
  32. "#897EC8",
  33. "#967EC8",
  34. "#AE7EC8",
  35. "#B57EC8",
  36. "#C87EA5",
  37. }
  38. // Randomly choose one and return
  39. return colors[rand.Intn(len(colors))]
  40. }
  41. func ParseEmojis(s string) template.HTML {
  42. emojiList := map[string]string{
  43. "normal": "101",
  44. "surprise": "102",
  45. "serious": "103",
  46. "heaven": "104",
  47. "happy": "105",
  48. "excited": "106",
  49. "sing": "107",
  50. "cry": "108",
  51. "normal2": "201",
  52. "shame2": "202",
  53. "love2": "203",
  54. "interesting2": "204",
  55. "blush2": "205",
  56. "fire2": "206",
  57. "angry2": "207",
  58. "shine2": "208",
  59. "panic2": "209",
  60. "normal3": "301",
  61. "satisfaction3": "302",
  62. "surprise3": "303",
  63. "smile3": "304",
  64. "shock3": "305",
  65. "gaze3": "306",
  66. "wink3": "307",
  67. "happy3": "308",
  68. "excited3": "309",
  69. "love3": "310",
  70. "normal4": "401",
  71. "surprise4": "402",
  72. "serious4": "403",
  73. "love4": "404",
  74. "shine4": "405",
  75. "sweat4": "406",
  76. "shame4": "407",
  77. "sleep4": "408",
  78. "heart": "501",
  79. "teardrop": "502",
  80. "star": "503",
  81. }
  82. regex := regexp.MustCompile(`\(([^)]+)\)`)
  83. parsedString := regex.ReplaceAllStringFunc(s, func(s string) string {
  84. s = s[1 : len(s)-1] // Get the string inside
  85. id := emojiList[s]
  86. return fmt.Sprintf(`<img src="/proxy/s.pximg.net/common/images/emoji/%s.png" alt="(%s)" class="emoji" />`, id, s)
  87. })
  88. return template.HTML(parsedString)
  89. }
  90. func ParsePixivRedirect(s string) template.HTML {
  91. regex := regexp.MustCompile(`\/jump\.php\?(http[^"]+)`)
  92. parsedString := regex.ReplaceAllStringFunc(s, func(s string) string {
  93. s = s[10:]
  94. return s
  95. })
  96. escaped, err := url.QueryUnescape(parsedString)
  97. if err != nil {
  98. return template.HTML(s)
  99. }
  100. return template.HTML(escaped)
  101. }
  102. func EscapeString(s string) string {
  103. escaped := url.QueryEscape(s)
  104. return escaped
  105. }
  106. func ParseTime(date time.Time) string {
  107. return date.Format("2006-01-02 15:04")
  108. }
  109. func CreatePaginator(base, ending string, current_page, max_page int) template.HTML {
  110. pageUrl := func(page int) string {
  111. return fmt.Sprintf(`%s%d%s`, base, page, ending)
  112. }
  113. const (
  114. peek = 5 // this can be changed freely
  115. limit = peek*2 + 1 // tied to the algorithm below, do not change
  116. )
  117. hasMaxPage := max_page != -1
  118. count := 0
  119. pages := ""
  120. pages += `<div class="pagination-buttons">`
  121. { // "jump to page" <form>
  122. hidden_section := ""
  123. urlParsed, err := url.Parse(base)
  124. if err != nil {
  125. panic(err)
  126. }
  127. for k, vs := range urlParsed.Query() {
  128. if k == "page" {
  129. continue
  130. }
  131. for _, v := range vs {
  132. hidden_section += fmt.Sprintf(`<input type="hidden" name="%s" value="%s"/>`, k, v)
  133. }
  134. }
  135. max_section := ""
  136. if hasMaxPage {
  137. max_section = fmt.Sprintf(`max="%d"`, max_page)
  138. }
  139. pages += fmt.Sprintf(`<form action="%s">%s<input name="page" type="number" required value="%d" min="%d" %s placeholder="Page№" title="Jump To Page Number"/></form>`, pageUrl(current_page), hidden_section, current_page, 1, max_section)
  140. pages += `<br />`
  141. }
  142. {
  143. // previous,first (two buttons)
  144. pages += `<span>`
  145. {
  146. pages += fmt.Sprintf(`<a href="%s" class="pagination-button">&laquo;</a>`, pageUrl(1))
  147. pages += fmt.Sprintf(`<a href="%s" class="pagination-button">&lsaquo;</a>`, pageUrl(max(1, current_page-1)))
  148. }
  149. pages += `</span>`
  150. // page number buttons
  151. for i := current_page - peek; (i <= max_page || max_page == -1) && count < limit; i++ {
  152. if i < 1 {
  153. continue
  154. }
  155. if i == current_page {
  156. pages += fmt.Sprintf(`<a href="%s" class="pagination-button" id="highlight">%d</a>`, pageUrl(i), i)
  157. } else {
  158. pages += fmt.Sprintf(`<a href="%s" class="pagination-button">%d</a>`, pageUrl(i), i)
  159. }
  160. count++
  161. }
  162. // next,last (two buttons)
  163. pages += `<span>`
  164. if hasMaxPage {
  165. pages += fmt.Sprintf(`<a href="%s" class="pagination-button">&rsaquo;</a>`, pageUrl(min(max_page, current_page+1)))
  166. pages += fmt.Sprintf(`<a href="%s" class="pagination-button">&raquo;</a>`, pageUrl(max_page))
  167. } else {
  168. pages += fmt.Sprintf(`<a href="%s" class="pagination-button">&rsaquo;</a>`, pageUrl(current_page+1))
  169. pages += fmt.Sprintf(`<a href="%s" class="pagination-button" class="disabled">&raquo;</a>`, pageUrl(max_page))
  170. }
  171. pages += `</span>`
  172. }
  173. pages += `</div>`
  174. return template.HTML(pages)
  175. }
  176. func GetNovelGenre(s string) string {
  177. switch s {
  178. case "1":
  179. return "Romance"
  180. case "2":
  181. return "Isekai fantasy"
  182. case "3":
  183. return "Contemporary fantasy"
  184. case "4":
  185. return "Mystery"
  186. case "5":
  187. return "Horror"
  188. case "6":
  189. return "Sci-fi"
  190. case "7":
  191. return "Literature"
  192. case "8":
  193. return "Drama"
  194. case "9":
  195. return "Historical pieces"
  196. case "10":
  197. return "BL (yaoi)"
  198. case "11":
  199. return "Yuri"
  200. case "12":
  201. return "For kids"
  202. case "13":
  203. return "Poetry"
  204. case "14":
  205. return "Essays/non-fiction"
  206. case "15":
  207. return "Screenplays/scripts"
  208. case "16":
  209. return "Reviews/opinion pieces"
  210. case "17":
  211. return "Other"
  212. }
  213. return fmt.Sprintf("(Unknown Genre %s)", s)
  214. }
  215. func SwitchButtonAttributes(baseURL, selection, currentSelection string) string {
  216. var cur string = "false"
  217. if selection == currentSelection {
  218. cur = "true"
  219. }
  220. return fmt.Sprintf(`href=%s%s class=switch-button selected=%s`, baseURL, selection, cur)
  221. }
  222. func lowercaseFirstChar(s string) string {
  223. return strings.ToLower(s[0:1]) + s[1:]
  224. }
  225. func GetTemplateFunctions() template.FuncMap {
  226. return template.FuncMap{
  227. "parseEmojis": func(s string) template.HTML {
  228. return ParseEmojis(s)
  229. },
  230. "parsePixivRedirect": func(s string) template.HTML {
  231. return ParsePixivRedirect(s)
  232. },
  233. "escapeString": func(s string) string {
  234. return EscapeString(s)
  235. },
  236. "randomColor": func() string {
  237. return GetRandomColor()
  238. },
  239. "isEmpty": func(s string) bool {
  240. return len(s) < 1
  241. },
  242. "isEmphasize": func(s string) bool {
  243. switch s {
  244. case
  245. "R-18",
  246. "R-18G":
  247. return true
  248. }
  249. return false
  250. },
  251. "reformatDate": func(s string) string {
  252. if len(s) != 8 {
  253. return s
  254. }
  255. return fmt.Sprintf("%s-%s-%s", s[4:], s[2:4], s[:2])
  256. },
  257. "parseTime": func(date time.Time) string {
  258. return ParseTime(date)
  259. },
  260. "createPaginator": func(base, ending string, current_page, max_page int) template.HTML {
  261. return CreatePaginator(base, ending, current_page, max_page)
  262. },
  263. "joinArtworkIds": func(artworks []core.ArtworkBrief) string {
  264. ids := []string{}
  265. for _, art := range artworks {
  266. ids = append(ids, art.ID)
  267. }
  268. return strings.Join(ids, ",")
  269. },
  270. "stripEmbed": func(s string) string {
  271. // this is stupid
  272. return s[:len(s)-6]
  273. },
  274. "renderNovel": func(s string) template.HTML {
  275. s = strings.ReplaceAll(s, "\n", "<br />")
  276. s = strings.ReplaceAll(s, "[newpage]", "Insert page separator here.")
  277. return template.HTML(s)
  278. },
  279. "novelGenre": GetNovelGenre,
  280. "floor": func(i float64) int {
  281. return int(math.Floor(i))
  282. },
  283. "URLC": func(obj site.URLConstructor, name string) string {
  284. url := fmt.Sprintf("/%s", obj.Path)
  285. first := true
  286. exists := false
  287. for k, v := range obj.Hash {
  288. k = lowercaseFirstChar(k)
  289. if k == name {
  290. // Reserve this
  291. exists = true
  292. continue
  293. }
  294. if v == "" {
  295. // If the value is empty, ignore to not clutter the URL
  296. continue
  297. }
  298. if first {
  299. url += "?"
  300. first = false
  301. } else {
  302. url += "&"
  303. }
  304. url += fmt.Sprintf("%s=%s", k, v)
  305. }
  306. // This is to move the matched query to the end of the URL
  307. if exists {
  308. var t string
  309. if first {
  310. t = "?"
  311. } else {
  312. t = "&"
  313. }
  314. url += fmt.Sprintf("%s%s=", t, name)
  315. }
  316. return url
  317. },
  318. "AttrGen": SwitchButtonAttributes,
  319. }
  320. }