dm.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. package model
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "hash/crc32"
  6. "strconv"
  7. )
  8. var (
  9. bAmp = []byte(`&`)
  10. bGt = []byte(`>`)
  11. bLt = []byte(`<`)
  12. bSp = []byte(` `)
  13. // <d p="播放时间,弹幕模式,字体大小,颜色,发送时间,弹幕池,用户hash,弹幕id">弹幕内容</d>
  14. _xmlFmt = `<d p="%.5f,%d,%d,%d,%d,%d,%s,%d">%s</d>`
  15. // <d p="播放时间,弹幕模式,字体大小,颜色,发送时间,弹幕池,用户hash,弹幕id,用户id">弹幕内容</d>
  16. _rnameFmt = `<d p="%.5f,%d,%d,%d,%d,%d,%s,%d,%d">%s</d>`
  17. )
  18. // All const variable use in job
  19. const (
  20. AttrNo = int32(0) // 属性位为0
  21. AttrYes = int32(1) // 属性位为1
  22. AttrProtect = uint(0) // 保护弹幕
  23. StateNormal = int32(0) // 普通状态
  24. StateDelete = int32(1) // 删除状态
  25. StateHide = int32(2) // 隐藏状态
  26. StateBlock = int32(3) // 屏蔽状态
  27. StateFilter = int32(4) // 过滤状态
  28. StateMonitorBefore = int32(5) // 先审后发
  29. StateMonitorAfter = int32(6) // 先发后审
  30. StateSystemFilter = int32(7) // 敏感词过滤
  31. StateReportDelete = int32(8) // 举报删除
  32. StateAdminDelete = int32(9) // 弹幕管理删除
  33. StateUserDelete = int32(10) // 用户删除
  34. StateScriptDelete = int32(11) // 举报脚本删除
  35. StateTaskDel = int32(12) //弹幕任务删除
  36. // 弹幕模式
  37. ModeRolling = int32(1)
  38. ModeBottom = int32(4)
  39. ModeTop = int32(5)
  40. ModeReverse = int32(6)
  41. ModeSpecial = int32(7)
  42. ModeCode = int32(8)
  43. ModeBAS = int32(9)
  44. PoolNormal = int32(0) // 普通弹幕池
  45. PoolSubtitle = int32(1) // 字幕弹幕池
  46. PoolSpecial = int32(2) // 特殊弹幕池
  47. MaskPriorityHgih = int32(1) // 弹幕蒙版优先级高
  48. MaskPriorityLow = int32(0) // 弹幕蒙版优先级低
  49. NotFound = int64(-1)
  50. )
  51. // BinlogMsg binlog msg produced by canal
  52. type BinlogMsg struct {
  53. Action string `json:"action"`
  54. Table string `json:"table"`
  55. New json.RawMessage `json:"new"`
  56. Old json.RawMessage `json:"old"`
  57. }
  58. // AttrVal return val of index'attr
  59. func (d *DM) AttrVal(bit uint) int32 {
  60. return (d.Attr >> bit) & int32(1)
  61. }
  62. // AttrSet set val of index'attr
  63. func (d *DM) AttrSet(v int32, bit uint) {
  64. d.Attr = d.Attr&(^(1 << bit)) | (v << bit)
  65. }
  66. // DMSlice dm array
  67. type DMSlice []*DM
  68. func (d DMSlice) Len() int { return len(d) }
  69. func (d DMSlice) Swap(i, j int) { d[i], d[j] = d[j], d[i] }
  70. func (d DMSlice) Less(i, j int) bool { return d[i].ID < d[j].ID }
  71. // ToXML convert dm struct to xml.
  72. func (d *DM) ToXML(realname bool) (s string) {
  73. if d.Content == nil {
  74. return
  75. }
  76. msg := d.Content.Msg
  77. if d.ContentSpe != nil {
  78. msg = d.ContentSpe.Msg
  79. }
  80. if len(msg) == 0 {
  81. return
  82. }
  83. if realname {
  84. // <d e="用户id" p="播放时间,弹幕模式,字体大小,颜色,发送时间,弹幕池,用户hash,弹幕id">弹幕内容</d>
  85. s = fmt.Sprintf(_rnameFmt, float64(d.Progress)/1000.0, d.Content.Mode, d.Content.FontSize, d.Content.Color, d.Ctime, d.Pool, hash(d.Mid, uint32(d.Content.IP)), d.ID, d.Mid, xmlReplace([]byte(msg)))
  86. } else {
  87. // <d p="播放时间,弹幕模式,字体大小,颜色,发送时间,弹幕池,用户hash,弹幕id">弹幕内容</d>
  88. s = fmt.Sprintf(_xmlFmt, float64(d.Progress)/1000.0, d.Content.Mode, d.Content.FontSize, d.Content.Color, d.Ctime, d.Pool, hash(d.Mid, uint32(d.Content.IP)), d.ID, xmlReplace([]byte(msg)))
  89. }
  90. return
  91. }
  92. // xmlReplace replace special char in xml.
  93. func xmlReplace(bi []byte) (bo []byte) {
  94. for _, b := range bi {
  95. if b == 0 {
  96. continue
  97. } else if b == '&' {
  98. bo = append(bo, bAmp...)
  99. continue
  100. } else if b == '>' {
  101. bo = append(bo, bGt...)
  102. continue
  103. } else if b == '<' {
  104. bo = append(bo, bLt...)
  105. continue
  106. } else if (b >= 0x01 && b <= 0x08) || (b >= 0x0b && b <= 0x0c) || (b >= 0x0e && b <= 0x1f) || (b == 0x7f) {
  107. bo = append(bo, bSp...)
  108. } else {
  109. bo = append(bo, b)
  110. }
  111. }
  112. return
  113. }
  114. // hash return hash string.
  115. func hash(mid int64, ip uint32) string {
  116. var s uint32
  117. if mid != 0 {
  118. s = crc32.ChecksumIEEE([]byte(strconv.FormatInt(mid, 10)))
  119. return strconv.FormatInt(int64(s), 16)
  120. }
  121. s = crc32.ChecksumIEEE([]byte(strconv.FormatInt(int64(ip), 10)))
  122. return "D" + strconv.FormatInt(int64(s), 16)
  123. }
  124. // GetSpecialSeg .
  125. func (d *DM) GetSpecialSeg() (msg string) {
  126. if d.Content == nil || d.Pool != PoolSpecial {
  127. return
  128. }
  129. msg = d.Content.Msg
  130. if d.ContentSpe != nil {
  131. msg = d.ContentSpe.Msg
  132. }
  133. return
  134. }
  135. // NeedDisplay 判断该条弹幕是否需要展示
  136. func (d *DM) NeedDisplay() bool {
  137. return d.State == StateNormal || d.State == StateMonitorAfter
  138. }
  139. // NeedUpdateSpecial .
  140. func (d *DM) NeedUpdateSpecial(old *DM) bool {
  141. if (d.Pool == PoolSpecial || old.Pool == PoolSpecial) && d.Pool != old.Pool {
  142. return true
  143. }
  144. if d.Pool == PoolSpecial && d.NeedDisplay() && !old.NeedDisplay() {
  145. return true
  146. }
  147. if d.Pool == PoolSpecial && old.NeedDisplay() && !d.NeedDisplay() {
  148. return true
  149. }
  150. return false
  151. }