github.com/chanxuehong/wechat@v0.0.0-20230222024006-36f0325263cd/mp/material/news.go (about) 1 package material 2 3 import ( 4 "fmt" 5 6 "github.com/chanxuehong/wechat/mp/core" 7 ) 8 9 type Article struct { 10 ThumbMediaId string `json:"thumb_media_id"` // 图文消息的封面图片素材id(必须是永久mediaID) 11 Title string `json:"title"` // 标题 12 Author string `json:"author,omitempty"` // 作者 13 Digest string `json:"digest,omitempty"` // 图文消息的摘要, 仅有单图文消息才有摘要, 多图文此处为空 14 Content string `json:"content"` // 图文消息的具体内容, 支持HTML标签, 必须少于2万字符, 小于1M, 且此处会去除JS 15 ContentSourceURL string `json:"content_source_url,omitempty"` // 图文消息的原文地址, 即点击"阅读原文"后的URL 16 ShowCoverPic int `json:"show_cover_pic"` // 是否显示封面, 0为false, 即不显示, 1为true, 即显示 17 URL string `json:"url,omitempty"` // !!!创建时不需要此参数!!! 图文页的URL, 文章创建成功以后, 会由微信自动生成 18 } 19 20 type News struct { 21 Articles []Article `json:"articles,omitempty"` 22 } 23 24 // 新增永久图文素材. 25 func AddNews(clt *core.Client, news *News) (mediaId string, err error) { 26 const incompleteURL = "https://api.weixin.qq.com/cgi-bin/material/add_news?access_token=" 27 28 var result struct { 29 core.Error 30 MediaId string `json:"media_id"` 31 } 32 if err = clt.PostJSON(incompleteURL, news, &result); err != nil { 33 return 34 } 35 if result.ErrCode != core.ErrCodeOK { 36 err = &result.Error 37 return 38 } 39 mediaId = result.MediaId 40 return 41 } 42 43 // 获取永久图文素材. 44 func GetNews(clt *core.Client, mediaId string) (news *News, err error) { 45 const incompleteURL = "https://api.weixin.qq.com/cgi-bin/material/get_material?access_token=" 46 47 var request = struct { 48 MediaId string `json:"media_id"` 49 }{ 50 MediaId: mediaId, 51 } 52 var result struct { 53 core.Error 54 Articles []Article `json:"news_item"` 55 } 56 if err = clt.PostJSON(incompleteURL, &request, &result); err != nil { 57 return 58 } 59 if result.ErrCode != core.ErrCodeOK { 60 err = &result.Error 61 return 62 } 63 news = &News{ 64 Articles: result.Articles, 65 } 66 return 67 } 68 69 // 修改永久图文素材. 70 func UpdateNews(clt *core.Client, mediaId string, index int, article *Article) (err error) { 71 const incompleteURL = "https://api.weixin.qq.com/cgi-bin/material/update_news?access_token=" 72 73 var request = struct { 74 MediaId string `json:"media_id"` 75 Index int `json:"index"` 76 Article *Article `json:"articles,omitempty"` 77 }{ 78 MediaId: mediaId, 79 Index: index, 80 Article: article, 81 } 82 var result core.Error 83 if err = clt.PostJSON(incompleteURL, &request, &result); err != nil { 84 return 85 } 86 if result.ErrCode != core.ErrCodeOK { 87 err = &result 88 return 89 } 90 return 91 } 92 93 type BatchGetNewsResult struct { 94 TotalCount int `json:"total_count"` // 该类型的素材的总数 95 ItemCount int `json:"item_count"` // 本次调用获取的素材的数量 96 Items []NewsInfo `json:"item"` // 本次调用获取的素材列表 97 } 98 99 type NewsInfo struct { 100 MediaId string `json:"media_id"` // 素材id 101 UpdateTime int64 `json:"update_time"` // 最后更新时间 102 Content struct { 103 Articles []Article `json:"news_item,omitempty"` 104 } `json:"content"` 105 } 106 107 // 获取图文素材列表. 108 // 109 // offset: 从全部素材的该偏移位置开始返回, 0表示从第一个素材 110 // count: 返回素材的数量, 取值在1到20之间 111 func BatchGetNews(clt *core.Client, offset, count int) (rslt *BatchGetNewsResult, err error) { 112 const incompleteURL = "https://api.weixin.qq.com/cgi-bin/material/batchget_material?access_token=" 113 114 if offset < 0 { 115 err = fmt.Errorf("Incorrect offset: %d", offset) 116 return 117 } 118 if count <= 0 { 119 err = fmt.Errorf("Incorrect count: %d", count) 120 return 121 } 122 123 var request = struct { 124 MaterialType string `json:"type"` 125 Offset int `json:"offset"` 126 Count int `json:"count"` 127 }{ 128 MaterialType: MaterialTypeNews, 129 Offset: offset, 130 Count: count, 131 } 132 var result struct { 133 core.Error 134 BatchGetNewsResult 135 } 136 if err = clt.PostJSON(incompleteURL, &request, &result); err != nil { 137 return 138 } 139 if result.ErrCode != core.ErrCodeOK { 140 err = &result.Error 141 return 142 } 143 rslt = &result.BatchGetNewsResult 144 return 145 } 146 147 // ===================================================================================================================== 148 149 // NewsIterator 150 // 151 // iter, err := NewNewsIterator(clt, 0, 10) 152 // if err != nil { 153 // // TODO: 增加你的代码 154 // } 155 // 156 // for iter.HasNext() { 157 // items, err := iter.NextPage() 158 // if err != nil { 159 // // TODO: 增加你的代码 160 // } 161 // // TODO: 增加你的代码 162 // } 163 type NewsIterator struct { 164 clt *core.Client 165 166 nextOffset int 167 count int 168 169 lastBatchGetNewsResult *BatchGetNewsResult 170 nextPageCalled bool 171 } 172 173 func (iter *NewsIterator) TotalCount() int { 174 return iter.lastBatchGetNewsResult.TotalCount 175 } 176 177 func (iter *NewsIterator) HasNext() bool { 178 if !iter.nextPageCalled { 179 return iter.lastBatchGetNewsResult.ItemCount > 0 || iter.nextOffset < iter.lastBatchGetNewsResult.TotalCount 180 } 181 return iter.nextOffset < iter.lastBatchGetNewsResult.TotalCount 182 } 183 184 func (iter *NewsIterator) NextPage() (items []NewsInfo, err error) { 185 if !iter.nextPageCalled { 186 iter.nextPageCalled = true 187 items = iter.lastBatchGetNewsResult.Items 188 return 189 } 190 191 rslt, err := BatchGetNews(iter.clt, iter.nextOffset, iter.count) 192 if err != nil { 193 return 194 } 195 196 iter.lastBatchGetNewsResult = rslt 197 iter.nextOffset += rslt.ItemCount 198 199 items = rslt.Items 200 return 201 } 202 203 func NewNewsIterator(clt *core.Client, offset, count int) (iter *NewsIterator, err error) { 204 // 逻辑上相当于第一次调用 NewsIterator.NextPage, 205 // 因为第一次调用 NewsIterator.HasNext 需要数据支撑, 所以提前获取了数据 206 rslt, err := BatchGetNews(clt, offset, count) 207 if err != nil { 208 return 209 } 210 211 iter = &NewsIterator{ 212 clt: clt, 213 214 nextOffset: offset + rslt.ItemCount, 215 count: count, 216 217 lastBatchGetNewsResult: rslt, 218 nextPageCalled: false, 219 } 220 return 221 }