1 | ;
|
2 |
|
3 | var path = require('path');
|
4 | var fs = require('fs');
|
5 |
|
6 | var formstream = require('formstream');
|
7 |
|
8 | var util = require('./util');
|
9 | var wrapper = util.wrapper;
|
10 | var postJSON = util.postJSON;
|
11 | var make = util.make;
|
12 |
|
13 | /**
|
14 | * 上传永久素材,分别有图片(image)、语音(voice)、和缩略图(thumb)
|
15 | * 详情请见:<http://mp.weixin.qq.com/wiki/14/7e6c03263063f4813141c3e17dd4350a.html>
|
16 | * Examples:
|
17 | * ```
|
18 | * api.uploadMaterial('filepath', type, callback);
|
19 | * ```
|
20 | * Callback:
|
21 | *
|
22 | * - `err`, 调用失败时得到的异常
|
23 | * - `result`, 调用正常时得到的对象
|
24 | *
|
25 | * Result:
|
26 | * ```
|
27 | * {"type":"TYPE","media_id":"MEDIA_ID","created_at":123456789}
|
28 | * ```
|
29 | * Shortcut:
|
30 | *
|
31 | * - `exports.uploadImageMaterial(filepath, callback);`
|
32 | * - `exports.uploadVoiceMaterial(filepath, callback);`
|
33 | * - `exports.uploadThumbMaterial(filepath, callback);`
|
34 | *
|
35 | * @param {String} filepath 文件路径
|
36 | * @param {String} type 媒体类型,可用值有image、voice、video、thumb
|
37 | * @param {Function} callback 回调函数
|
38 | */
|
39 | make(exports, 'uploadMaterial', function (filepath, type, callback) {
|
40 | var that = this;
|
41 | fs.stat(filepath, function (err, stat) {
|
42 | if (err) {
|
43 | return callback(err);
|
44 | }
|
45 | var form = formstream();
|
46 | form.file('media', filepath, path.basename(filepath), stat.size);
|
47 | var url = that.endpoint + '/cgi-bin/material/add_material?access_token=' + that.token.accessToken + '&type=' + type;
|
48 | var opts = {
|
49 | dataType: 'json',
|
50 | type: 'POST',
|
51 | timeout: 60000, // 60秒超时
|
52 | headers: form.headers(),
|
53 | stream: form
|
54 | };
|
55 | that.request(url, opts, wrapper(callback));
|
56 | });
|
57 | });
|
58 |
|
59 | ['image', 'voice', 'thumb'].forEach(function (type) {
|
60 | var method = 'upload' + type[0].toUpperCase() + type.substring(1) + 'Material';
|
61 | exports[method] = function (filepath, callback) {
|
62 | this.uploadMaterial(filepath, type, callback);
|
63 | };
|
64 | });
|
65 |
|
66 | /**
|
67 | * 上传永久素材,视频(video)
|
68 | * 详情请见:<http://mp.weixin.qq.com/wiki/14/7e6c03263063f4813141c3e17dd4350a.html>
|
69 | * Examples:
|
70 | * ```
|
71 | * var description = {
|
72 | * "title":VIDEO_TITLE,
|
73 | * "introduction":INTRODUCTION
|
74 | * };
|
75 | * api.uploadVideoMaterial('filepath', description, callback);
|
76 | * ```
|
77 | * Callback:
|
78 | *
|
79 | * - `err`, 调用失败时得到的异常
|
80 | * - `result`, 调用正常时得到的对象
|
81 | *
|
82 | * Result:
|
83 | * ```
|
84 | * {"media_id":"MEDIA_ID"}
|
85 | * ```
|
86 | *
|
87 | * @param {String} filepath 视频文件路径
|
88 | * @param {Object} description 描述
|
89 | * @param {Function} callback 回调函数
|
90 | */
|
91 | make(exports, 'uploadVideoMaterial', function (filepath, description, callback) {
|
92 | var that = this;
|
93 | fs.stat(filepath, function (err, stat) {
|
94 | if (err) {
|
95 | return callback(err);
|
96 | }
|
97 | var form = formstream();
|
98 | form.file('media', filepath, path.basename(filepath), stat.size);
|
99 | form.field('description', JSON.stringify(description));
|
100 | var url = that.endpoint + '/cgi-bin/material/add_material?access_token=' + that.token.accessToken + '&type=video';
|
101 | var opts = {
|
102 | dataType: 'json',
|
103 | type: 'POST',
|
104 | timeout: 60000, // 60秒超时
|
105 | headers: form.headers(),
|
106 | stream: form
|
107 | };
|
108 | that.request(url, opts, wrapper(callback));
|
109 | });
|
110 | });
|
111 |
|
112 | /**
|
113 | * 新增永久图文素材
|
114 | *
|
115 | * News:
|
116 | * ```
|
117 | * {
|
118 | * "articles": [
|
119 | * {
|
120 | * "title": TITLE,
|
121 | * "thumb_media_id": THUMB_MEDIA_ID,
|
122 | * "author": AUTHOR,
|
123 | * "digest": DIGEST,
|
124 | * "show_cover_pic": SHOW_COVER_PIC(0 / 1),
|
125 | * "content": CONTENT,
|
126 | * "content_source_url": CONTENT_SOURCE_URL
|
127 | * },
|
128 | * //若新增的是多图文素材,则此处应还有几段articles结构
|
129 | * ]
|
130 | * }
|
131 | * ```
|
132 | * Examples:
|
133 | * ```
|
134 | * api.uploadNewsMaterial(news, callback);
|
135 | * ```
|
136 | * Callback:
|
137 | *
|
138 | * - `err`, 调用失败时得到的异常
|
139 | * - `result`, 调用正常时得到的对象
|
140 | *
|
141 | * Result:
|
142 | * ```
|
143 | * {"errcode":0,"errmsg":"ok"}
|
144 | * ```
|
145 | * @param {Object} news 图文对象
|
146 | * @param {Function} callback 回调函数
|
147 | */
|
148 | exports.uploadNewsMaterial = function (news, callback) {
|
149 | this.preRequest(this._uploadNewsMaterial, arguments);
|
150 | };
|
151 |
|
152 | /*!
|
153 | * 新增永久图文素材的未封装版本
|
154 | */
|
155 | exports._uploadNewsMaterial = function (news, callback) {
|
156 | var url = this.endpoint + '/cgi-bin/material/add_news?access_token=' + this.token.accessToken;
|
157 | this.request(url, postJSON(news), wrapper(callback));
|
158 | };
|
159 |
|
160 |
|
161 | /**
|
162 | * 更新永久图文素材
|
163 | * 详情请见:<http://mp.weixin.qq.com/wiki/14/7e6c03263063f4813141c3e17dd4350a.html>
|
164 | * News:
|
165 | * ```
|
166 | * {
|
167 | * "media_id":MEDIA_ID,
|
168 | * "index":INDEX,
|
169 | * "articles": {
|
170 | * "title": TITLE,
|
171 | * "thumb_media_id": THUMB_MEDIA_ID,
|
172 | * "author": AUTHOR,
|
173 | * "digest": DIGEST,
|
174 | * "show_cover_pic": SHOW_COVER_PIC(0 / 1),
|
175 | * "content": CONTENT,
|
176 | * "content_source_url": CONTENT_SOURCE_URL
|
177 | * }
|
178 | * }
|
179 | * ```
|
180 | * Examples:
|
181 | * ```
|
182 | * api.updateNewsMaterial(news, callback);
|
183 | * ```
|
184 | * Callback:
|
185 | *
|
186 | * - `err`, 调用失败时得到的异常
|
187 | * - `result`, 调用正常时得到的对象
|
188 | *
|
189 | * Result:
|
190 | * ```
|
191 | * {"errcode":0,"errmsg":"ok"}
|
192 | * ```
|
193 | * @param {Object} news 图文对象
|
194 | * @param {Function} callback 回调函数
|
195 | */
|
196 | exports.updateNewsMaterial = function (news, callback) {
|
197 | this.preRequest(this._updateNewsMaterial, arguments);
|
198 | };
|
199 |
|
200 | /*!
|
201 | * 更新永久图文素材的未封装版本
|
202 | */
|
203 | exports._updateNewsMaterial = function (news, callback) {
|
204 | var url = this.endpoint + '/cgi-bin/material/update_news?access_token=' + this.token.accessToken;
|
205 | this.request(url, postJSON(news), wrapper(callback));
|
206 | };
|
207 |
|
208 |
|
209 | /**
|
210 | * 根据媒体ID获取永久素材
|
211 | * 详情请见:<http://mp.weixin.qq.com/wiki/4/b3546879f07623cb30df9ca0e420a5d0.html>
|
212 | * Examples:
|
213 | * ```
|
214 | * api.getMaterial('media_id', callback);
|
215 | * ```
|
216 | * Callback:
|
217 | *
|
218 | * - `err`, 调用失败时得到的异常
|
219 | * - `result`, 调用正常时得到的文件Buffer对象
|
220 | * - `res`, HTTP响应对象
|
221 | *
|
222 | * @param {String} mediaId 媒体文件的ID
|
223 | * @param {Function} callback 回调函数
|
224 | */
|
225 | exports.getMaterial = function (mediaId, callback) {
|
226 | this.preRequest(this._getMaterial, arguments);
|
227 | };
|
228 |
|
229 | /*!
|
230 | * 下载永久素材的未封装版本
|
231 | */
|
232 | exports._getMaterial = function (mediaId, callback) {
|
233 | var url = this.endpoint + '/cgi-bin/material/get_material?access_token=' + this.token.accessToken;
|
234 | var opts = {
|
235 | type: 'POST',
|
236 | data: {'media_id': mediaId},
|
237 | headers: {
|
238 | 'Content-Type': 'application/json'
|
239 | }
|
240 | };
|
241 | opts.timeout = 60000; // 60秒超时
|
242 | this.request(url, opts, wrapper(function (err, data, res) {
|
243 | // handle some err
|
244 | if (err) {
|
245 | return callback(err);
|
246 | }
|
247 | var contentType = res.headers['content-type'];
|
248 | if (contentType === 'application/json') {
|
249 | var ret;
|
250 | try {
|
251 | ret = JSON.parse(data);
|
252 | if (ret.errcode) {
|
253 | err = new Error(ret.errmsg);
|
254 | err.name = 'WeChatAPIError';
|
255 | }
|
256 | } catch (ex) {
|
257 | return callback(ex, data, res);
|
258 | }
|
259 | return callback(err, ret, res);
|
260 | }
|
261 | // 输出Buffer对象
|
262 | callback(null, data, res);
|
263 | }));
|
264 | };
|
265 |
|
266 | /**
|
267 | * 删除永久素材
|
268 | * 详情请见:<http://mp.weixin.qq.com/wiki/5/e66f61c303db51a6c0f90f46b15af5f5.html>
|
269 | * Examples:
|
270 | * ```
|
271 | * api.removeMaterial('media_id', callback);
|
272 | * ```
|
273 | * Callback:
|
274 | *
|
275 | * - `err`, 调用失败时得到的异常
|
276 | * - `result`, 调用正常时得到的文件Buffer对象
|
277 | * - `res`, HTTP响应对象
|
278 | *
|
279 | * @param {String} mediaId 媒体文件的ID
|
280 | * @param {Function} callback 回调函数
|
281 | */
|
282 | exports.removeMaterial = function (mediaId, callback) {
|
283 | this.preRequest(this._removeMaterial, arguments);
|
284 | };
|
285 |
|
286 | /*!
|
287 | * 删除永久素材的未封装版本
|
288 | */
|
289 | exports._removeMaterial = function (mediaId, callback) {
|
290 | var url = this.endpoint + '/cgi-bin/material/del_material?access_token=' + this.token.accessToken;
|
291 | this.request(url, postJSON({'media_id': mediaId}), wrapper(callback));
|
292 | };
|
293 |
|
294 |
|
295 | /**
|
296 | * 获取素材总数
|
297 | * 详情请见:<http://mp.weixin.qq.com/wiki/16/8cc64f8c189674b421bee3ed403993b8.html>
|
298 | * Examples:
|
299 | * ```
|
300 | * api.getMaterialCount(callback);
|
301 | * ```
|
302 | * Callback:
|
303 | *
|
304 | * - `err`, 调用失败时得到的异常
|
305 | * - `result`, 调用正常时得到的文件Buffer对象
|
306 | * - `res`, HTTP响应对象
|
307 | *
|
308 | * Result:
|
309 | * ```
|
310 | * {
|
311 | * "voice_count":COUNT,
|
312 | * "video_count":COUNT,
|
313 | * "image_count":COUNT,
|
314 | * "news_count":COUNT
|
315 | * }
|
316 | * ```
|
317 | * @param {Function} callback 回调函数
|
318 | */
|
319 | exports.getMaterialCount = function (callback) {
|
320 | this.preRequest(this._getMaterialCount, arguments);
|
321 | };
|
322 |
|
323 |
|
324 |
|
325 | /*!
|
326 | * 删除永久素材的未封装版本
|
327 | */
|
328 | exports._getMaterialCount = function (callback) {
|
329 | var url = this.endpoint + '/cgi-bin/material/get_materialcount?access_token=' + this.token.accessToken;
|
330 | this.request(url, {dataType: 'json'}, wrapper(callback));
|
331 | };
|
332 |
|
333 | /**
|
334 | * 获取永久素材列表
|
335 | * 详情请见:<http://mp.weixin.qq.com/wiki/12/2108cd7aafff7f388f41f37efa710204.html>
|
336 | * Examples:
|
337 | * ```
|
338 | * api.getMaterials(type, offset, count, callback);
|
339 | * ```
|
340 | * Callback:
|
341 | *
|
342 | * - `err`, 调用失败时得到的异常
|
343 | * - `result`, 调用正常时得到的文件Buffer对象
|
344 | * - `res`, HTTP响应对象
|
345 | *
|
346 | * Result:
|
347 | * ```
|
348 | * {
|
349 | * "total_count": TOTAL_COUNT,
|
350 | * "item_count": ITEM_COUNT,
|
351 | * "item": [{
|
352 | * "media_id": MEDIA_ID,
|
353 | * "name": NAME,
|
354 | * "update_time": UPDATE_TIME
|
355 | * },
|
356 | * //可能会有多个素材
|
357 | * ]
|
358 | * }
|
359 | * ```
|
360 | * @param {String} type 素材的类型,图片(image)、视频(video)、语音 (voice)、图文(news)
|
361 | * @param {Number} offset 从全部素材的该偏移位置开始返回,0表示从第一个素材 返回
|
362 | * @param {Number} count 返回素材的数量,取值在1到20之间
|
363 | * @param {Function} callback 回调函数
|
364 | */
|
365 | exports.getMaterials = function (type, offset, count, callback) {
|
366 | this.preRequest(this._getMaterials, arguments);
|
367 | };
|
368 |
|
369 |
|
370 |
|
371 | /*!
|
372 | * 获取永久素材列表的未封装版本
|
373 | */
|
374 | exports._getMaterials = function (type, offset, count, callback) {
|
375 | var url = this.endpoint + '/cgi-bin/material/batchget_material?access_token=' + this.token.accessToken;
|
376 | var data = {
|
377 | type: type,
|
378 | offset: offset,
|
379 | count: count
|
380 | };
|
381 | this.request(url, postJSON(data), wrapper(callback));
|
382 | };
|