GraphQL API and utilities for the rpdata project
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

92 lines
2.3 KiB

  1. package mirclike
  2. import (
  3. "errors"
  4. "strconv"
  5. "strings"
  6. "time"
  7. "git.aiterp.net/rpdata/api/models"
  8. )
  9. // ErrNotPost is returned by parsePost if the line is empty or not a post.
  10. var ErrNotPost = errors.New("not a post")
  11. // ParsePost parses a post from a mirc-like line. If the previous post is included (it can be empty), it will be used
  12. // to determine whether midnight has passed.
  13. func ParsePost(line string, date time.Time, prev models.Post) (models.Post, error) {
  14. // Do basic validation
  15. line = strings.Trim(line, "  \t\n\r")
  16. if len(line) == 0 || !strings.HasPrefix(line, "[") {
  17. return models.Post{}, ErrNotPost
  18. }
  19. // Parse timestamp
  20. tsEndIndex := strings.IndexByte(line, ']')
  21. if tsEndIndex == -1 || len(line) < tsEndIndex+5 {
  22. return models.Post{}, ErrNotPost
  23. }
  24. tsStr := line[1:tsEndIndex]
  25. tsSplit := strings.Split(tsStr, ":")
  26. tsUnits := make([]int, len(tsSplit))
  27. if len(tsSplit) < 2 {
  28. return models.Post{}, ErrNotPost
  29. }
  30. for i := range tsSplit {
  31. n, err := strconv.Atoi(tsSplit[i])
  32. if err != nil {
  33. return models.Post{}, ErrNotPost
  34. }
  35. tsUnits[i] = n
  36. }
  37. if len(tsUnits) == 2 {
  38. tsUnits = append(tsUnits, 0)
  39. }
  40. // Determine timestamp from parsed data and previous post.
  41. ts := time.Date(date.Year(), date.Month(), date.Day(), tsUnits[0], tsUnits[1], tsUnits[2], 0, date.Location())
  42. if !prev.Time.IsZero() && prev.Time.Sub(ts) > 30*time.Minute {
  43. ts = time.Date(prev.Time.Year(), prev.Time.Month(), prev.Time.Day()+1, tsUnits[0], tsUnits[1], tsUnits[2], 0, date.Location())
  44. }
  45. if line[tsEndIndex+2] == '*' {
  46. split := strings.SplitN(line[tsEndIndex+4:], " ", 2)
  47. post := models.Post{
  48. ID: "UNASSIGNED",
  49. LogID: "UNASSIGNED",
  50. Time: ts,
  51. Kind: "action",
  52. Nick: strings.TrimLeft(split[0], "+@!~"),
  53. Text: split[1],
  54. Position: prev.Position + 1,
  55. }
  56. if post.Nick[0] == '=' {
  57. post.Kind = "scene"
  58. }
  59. return post, nil
  60. } else if line[tsEndIndex+2] == '<' {
  61. split := strings.SplitN(line[tsEndIndex+2:], " ", 2)
  62. post := models.Post{
  63. ID: "UNASSIGNED",
  64. LogID: "UNASSIGNED",
  65. Time: ts,
  66. Kind: "text",
  67. Nick: strings.TrimLeft(split[0][1:len(split[0])-1], "+@!~"),
  68. Text: split[1],
  69. Position: prev.Position + 1,
  70. }
  71. if post.Nick[0] == '=' {
  72. post.Kind = "scene"
  73. }
  74. return post, nil
  75. } else {
  76. return models.Post{}, ErrNotPost
  77. }
  78. }