module.exports = Snaps var debug = require('debug')('snapchat:snaps') var Promise = require('bluebird') var constants = require('../lib/constants') var StringUtils = require('../lib/string-utils') var Request = require('../lib/request') var SnapOptions = require('../models/snap-options') var SKBlob = require('../models/blob') var SKLocation = require('../models/location') /** * Snapchat wrapper for Snap-related API calls. * * @class * @param {Object} opts */ function Snaps (client, opts) { var self = this if (!(self instanceof Snaps)) return new Snaps(client, opts) if (!opts) opts = {} self.client = client } /** * Sends a snap to everyone in recipients with text text for duration seconds. * * @param {SKBlob} blob The SKBlob object containing the image or video data to send. Can be created with any NSData object. * @param {Array<string>|string} recipients An array of username strings. * @param {string} text The text to label the snap with. This text is not superimposed upon the image; you must do that yourself. * @param {number} duration The length of the snap. It must be greater than 0 or an exception will be raised. * @param {function} cb */ Snaps.prototype.sendSnap = function (blob, recipients, text, duration, cb) { var self = this debug('Snaps.sendSnap') return self.sendSnapCustom(blob, new SnapOptions(recipients, text, duration), cb) } /** * Sends a snap with the given options. * * @param {SKBlob} blob The SKBlob object containing the image or video data to send. Can be created with any Buffer. * @param {SnapOptions} opts The options for the snap to be sent. * @param {function} cb */ Snaps.prototype.sendSnapCustom = function (blob, opts, cb) { var self = this return new Promise(function (resolve, reject) { debug('Snaps.sendSnapCustom') self._uploadSnap(blob, function (err, mediaID) { if (err) { return reject(err) } self.client.post(constants.endpoints.snaps.send, { 'camera_front_facing': !!opts.cameraFrontFacing, 'country_code': self.client.session.countryCode, 'media_id': mediaID, 'recipients': JSON.stringify(opts.recipients), 'recipient_ids': JSON.stringify(opts.recipients), 'reply': !!opts.isReply, 'time': +opts.timer, 'zipped': 0, 'username': self.client.username }, function (err, result) { if (err) { return reject(err) } return resolve(result) }) }) }).nodeify(cb) } /** * Marks a snap as opened for secondsViewed seconds. * * @param {number} secondsViewed The number of seconds the snap was viewed for. * @param {function} cb */ Snaps.prototype.markSnapViewed = function (snap, secondsViewed, cb) { var self = this debug('Snaps.markSnapViewed') return self.markSnapsViewed([ snap ], [ new Date() ], [ secondsViewed ], cb) } /** * Marks a set of snaps as opened for the specified length at the given times. * * @param {Array<SKSnap>} snaps An array of SKSnap objects. * @param {Array<Date>} times An array of Date objects. * @param {Array<number>} secondsViewed An array of numbers. * @param {function} cb */ Snaps.prototype.markSnapsViewed = function (snaps, times, secondsViewed, cb) { var self = this debug('Snaps.markSnapsViewed') if (snaps.length !== times.length || times.length !== secondsViewed.length) { throw new Error('Snaps.markSnapsViewed all arrays must have the same length') } var json = { } snaps.forEach(function (snap, index) { json[snap.identifier] = { 't': StringUtils.timestampFrom(times[index]), 'sv': secondsViewed[index] } }) return self.client.post(constants.endpoints.update.snaps, { 'added_friends_timestamp': StringUtils.timestampFrom(self.session.addedFriendsTimestamp), 'username': self.client.username, 'json': JSON.stringify(json) }, cb) } /** * Marks a snap as screenshotted and viewed for secondsViewed seconds. * * @param {number} secondsViewed The number of seconds the snap was viewed for. * @param {function} cb */ Snaps.prototype.markSnapScreenshot = function (snap, secondsViewed, cb) { var self = this debug('Snaps.markSnapScreenshot') var timestamp = StringUtils.timestamp() var snapInfo = { } snapInfo[snap.identifier] = { 't': timestamp | 0, 'sv': secondsViewed, 'c': constants.SnapStatus.Screenshot } var screenshot = { 'eventName': 'SNAP_SCREENSHOT', 'params': { 'id': snap.identifier }, 'ts': StringUtils.timestamp() | 0 } return self.client.sendEvents([ screenshot ], snapInfo, cb) } /** * Loads a snap. * * @param {Snap} snap * @param {function} cb */ Snaps.prototype.loadSnap = function (snap, cb) { var self = this debug('Snaps.loadSnap') return self._loadSnapWithIdentifier(snap.identifier, cb) } /** * Loads filters for a location. * * @param {Object} location { lat, lng } * @param {function} cb */ Snaps.prototype.loadFiltersForLocation = function (location, cb) { var self = this return new Promise(function (resolve, reject) { debug('Snaps.loadFiltersForLocation') self.client.post(constants.endpoints.misc.locationData, { 'lat': location.lat, 'lng': location.lng, 'screen_width': self.client.screenSize.width, 'screen_height': self.client.screenSize.height, 'username': self.client.username }, function (err, result) { if (err) { return reject(err) } else if (result) { return resolve(new SKLocation(result)) } return reject(new Error('Snaps.loadFiltersForLocation parse error')) }) }).nodeify(cb) } /** * @private */ Snaps.prototype._loadSnapWithIdentifier = function (identifier, cb) { var self = this return new Promise(function (resolve, reject) { self.client.post(constants.endpoints.snaps.loadBlob, { 'id': identifier, 'username': self.client.username }, function (err, body) { if (err) { return reject(err) } SKBlob.initWithData(body, function (err, blob) { if (err) { return reject(err) } return resolve(blob) }) }) }).nodeify(cb) } /** * @private * @param {SKBlob} blob * @param {function} cb */ Snaps.prototype._uploadSnap = function (blob, cb) { var self = this var uuid = StringUtils.mediaIdentifier(self.client.username) if (!(blob instanceof SKBlob)) { throw new Error('Snap._uploadSnap invalid argument "blob" must be SKBlob instance') } var params = { 'media_id': uuid, 'type': blob.isImage ? constants.MediaKind.Image.value : constants.MediaKind.Video.value, 'data': blob.data, 'zipped': 0, 'features_map': '{}', 'username': self.client.username } var headers = { } headers[constants.headers.clientAuthToken] = 'Bearer ' + self.client.googleAuthToken headers[constants.headers.contentType] = 'multipart/form-data; boundary=' + constants.core.boundary Request.postCustom(constants.endpoints.snaps.upload, params, headers, self.client.authToken, function (err) { if (err) { return cb(err) } else { return cb(null, uuid) } }) }