func (t *TemplateField) Unique() {
	seen := make(map[uint64]struct{}, len(t.Comments))
	j := 0
	for _, v := range t.Comments {
		if _, ok := seen[v.PostNO]; ok {
			continue
		}
		seen[v.PostNO] = struct{}{}
		t.Comments[j] = v
		j++
	}
	t.Comments = t.Comments[:j]
}
Unique removes any duplicate posts using PoseNO
package main
import (
	"encoding/json"
	"html/template"
	"net/url"
	"sync"
	"sync/atomic"
)
type PageChannel struct {
	rec <-chan *HTMLPage
	send chan<- *HTMLPage
	ref int64
	init int64
}
func (p *PageChannel) Add(n int64) {
	if n <= 0 {
		return
	}
	atomic.AddInt64(&p.ref, n)
}
func (p *PageChannel) Del(n int64) {
	if n <= 0 {
		return
	}
	atomic.AddInt64(&p.ref, -n)
}
func (p *PageChannel) Ref() int64 {
	return atomic.LoadInt64(&p.ref)
}
func (p *PageChannel) Inited() {
	atomic.StoreInt64(&p.init, 1)
}
func (p *PageChannel) IsDone() bool {
	return atomic.LoadInt64(&p.ref) <= 0 && atomic.LoadInt64(&p.init) != 0
}
type HTMLType int
const (
	HTMLWebHomepage HTMLType = iota
	HTMLWebPage
	HTMLJSON
	HTMLLzlHome
	HTMLLzl
	HTMLLocal
	HTMLWebWAPHomepage
	HTMLWebWAPPage
)
type HTMLPage struct {
	URL *url.URL
	Content []byte
	Type HTMLType
}
type TiebaField struct {
	Author struct {
		UserID   uint64 `json:"user_id"`
		UserName string `json:"user_name"`  
	} `json:"author"`
	Content struct {
		PostID uint64 `json:"post_id"`
		ForumID  uint64 `json:"forum_id"`
		ThreadID uint64 `json:"thread_id"`
		Content  string `json:"content"`  
		PostNO   uint64 `json:"post_no"`  
	} `json:"content"`
}
type LzlField struct {
	ErrNO  int64                      `json:"errno"`
	ErrMsg string                     `json:"errmsg"`
	Data   map[string]json.RawMessage `json:"data"`
}
type LzlContent struct {
	Index     int64
	UserName  string        `json:"username"`
	Content   template.HTML `json:"content"`
	Timestamp int64         `json:"now_time"`
	Time      string
}
type LzlComment struct {
	Num     uint64        `json:"comment_num"`
	ListNum uint64        `json:"comment_list_num"`
	Info    []*LzlContent `json:"comment_info"`
}
type LzlPageComment struct {
	TotalNum  uint64 `json:"total_num"`
	TotalPage uint64 `json:"total_page"`
}
type OutputField struct {
	UserName template.HTML
	Content  template.HTML
	PostNO   uint64
	PostID   uint64
	Time     string
}
type LzlMap struct {
	Map  map[uint64]*LzlComment
	lock *sync.Mutex
}
func (lzl *LzlMap) Append(k uint64, c *LzlContent) {
	lzl.lock.Lock()
	lzl.Map[k].Info = append(lzl.Map[k].Info, c)
	lzl.lock.Unlock()
}
func (lzl *LzlMap) Insert(k uint64, v *LzlComment) {
	lzl.lock.Lock()
	lzl.Map[k] = v
	lzl.lock.Unlock()
}
func (lzl *LzlMap) IsExist(k uint64) bool {
	lzl.lock.Lock()
	_, ok := lzl.Map[k]
	lzl.lock.Unlock()
	return ok
}
type TemplateField struct {
	Title     string
	Url       string
	ThreadID  uint64
	Comments  []*OutputField
	pagesLeft int64
	Lzls      *LzlMap  
	lzlsLeft  int64
	mutex     *sync.RWMutex
	send      bool
}
func (t *TemplateField) Send(c chan *TemplateField) {
	t.mutex.RLock()
	if !t.send {
		t.mutex.RUnlock()
		t.mutex.Lock()
		if !t.send {
			c <- t
			t.send = true
		}
		t.mutex.Unlock()
	} else {
		t.mutex.RUnlock()
	}
}
func (t *TemplateField) AddPage(n int64) {
	atomic.AddInt64(&t.pagesLeft, n)
}
func (t *TemplateField) AddLzl(n int64) {
	atomic.AddInt64(&t.lzlsLeft, n)
}
func (t *TemplateField) Append(post *OutputField) {
	t.mutex.Lock()
	t.Comments = append(t.Comments, post)
	t.mutex.Unlock()
}
func (t *TemplateField) IsDone() bool {
	pagesLeft := atomic.LoadInt64(&t.pagesLeft)
	lzlsLeft := atomic.LoadInt64(&t.lzlsLeft)
	return pagesLeft <= 0 && lzlsLeft <= 0
}
func (t *TemplateField) Merge() {
	l := len(t.Comments)
	for i := 0; i+1 < l; i++ {
		if t.Comments[i+1].UserName != t.Comments[i].UserName {
			continue
		}
		v, ok := t.Lzls.Map[t.Comments[i+1].PostID]
		if ok && v.ListNum != 0 && v.Num != 0 {
			continue
		}
		v, ok = t.Lzls.Map[t.Comments[i].PostID]
		if ok && v.ListNum != 0 && v.Num != 0 {
			continue
		}
		bs := make([]byte, len(t.Comments[i].Content)+len(t.Comments[i+1].Content)+1)
		bl := 0
		bl += copy(bs[bl:], t.Comments[i].Content)
		bs[bl] = '\n'
		bl++
		bl += copy(bs[bl:], t.Comments[i+1].Content)
		t.Comments[i].Content = template.HTML(bs)
		t.Comments = append(t.Comments[:i+1], t.Comments[i+2:]...)
		i--
		l--
	}
}