Source: models/blob.js

module.exports = SKBlob

var BufferUtils = require('../lib/buffer-utils')
var Story = require('./story')
var fileType = require('file-type')
var JSZip = require('jszip')

/**
 * Snapchat Blob wrapper
 *
 * @class
 * @param {Buffer} data
 */
function SKBlob (data) {
  var self = this
  if (!(self instanceof SKBlob)) return new SKBlob(data)

  if (!(data instanceof Buffer)) {
    data = new Buffer(data)
  }

  self._data = data
  self._type = fileType(data)

  self._isImage = BufferUtils.isImage(data)
  self._isMPEG4 = BufferUtils.isMPEG4(data)
  self._isVideo = self._isMPEG4
  self._isMedia = BufferUtils.isMedia(data)

  // TODO
  self._overlay = null
}

/**
 * The underlying data for the image or video.
 *
 * @name SKBlob#data
 * @property {Buffer}
 * @readonly
 */
Object.defineProperty(SKBlob.prototype, 'data', {
  get: function () { return this._data }
})

/**
 * Information about the media type.
 *
 * @name SKBlob#type
 * @property {Buffer}
 * @readonly
 */
Object.defineProperty(SKBlob.prototype, 'type', {
  get: function () { return this._type }
})

/**
 * The overlay for the video if applicable.
 *
 * @name SKBlob#overlay
 * @property {Buffer}
 * @readonly
 */
Object.defineProperty(SKBlob.prototype, 'overlay', {
  get: function () { return this._overlay }
})

/**
 * Whether or not this blob represents an image (PNG or JPEG).
 *
 * @name SKBlob#isImage
 * @property {boolean}
 * @readonly
 */
Object.defineProperty(SKBlob.prototype, 'isImage', {
  get: function () { return this._isImage }
})

/**
 * Whether or not this blob represents a video (MPEG4).
 *
 * @name SKBlob#isVideo
 * @property {boolean}
 * @readonly
 */
Object.defineProperty(SKBlob.prototype, 'isVideo', {
  get: function () { return this._isVideo }
})

/**
 * Whether or not this blob represents an MPEG4 video.
 *
 * @name SKBlob#isMPEG4
 * @property {boolean}
 * @readonly
 */
Object.defineProperty(SKBlob.prototype, 'isMPEG4', {
  get: function () { return this._isMPEG4 }
})

/**
 * Whether or not this blob represents a supported image or video format.
 *
 * @name SKBlob#isMedia
 * @property {boolean}
 * @readonly
 */
Object.defineProperty(SKBlob.prototype, 'isMedia', {
  get: function () { return this._isMedia }
})

/**
 * Initializes and returns a new SKBlob from the given raw data.
 * Does not handle encrypted data.
 *
 * @static
 * @param {Buffer} data
 * @param {function} cb
 */
SKBlob.initWithData = function (data, cb) {
  if (!data) {
    return cb('error empty blob')
  }

  if (typeof data === 'string') {
    data = new Buffer(data)
  }

  if (BufferUtils.isCompressed(data)) {
    var files = SKBlob.decompress(data)
    return cb(null, files)
  }

  var blob = new SKBlob(data)
  return cb(blob.isMedia ? null : 'unknown blob format', blob)
}

/**
 * Initializes and returns a new SKBlob from the given story and raw data.
 *
 * @static
 * @param {Buffer} data
 * @param {Story} story
 * @param {function} cb
 */
SKBlob.initWithStoryData = function (data, story, cb) {
  if (!(story instanceof Story)) {
    throw new Error('SKBlob.initWithStoryData invalid story')
  }

  if (typeof data === 'string') {
    data = new Buffer(data)
  }

  if (BufferUtils.isCompressed(data)) {
    var files = SKBlob.decompress(data)
    return cb(null, files)
  }

  return SKBlob.decrypt(data, story, cb)
}

/**
 * Unarchives blobs initialized with anonymous data.
 *
 * @static
 * @param {Buffer} data
 * @param {function} cb
 */
SKBlob.decompress = function (data, cb) {
  var zip = new JSZip(data)
  var files = Object.keys(zip.files).map(function (filename) {
    var decompressed = zip.file(filename).asNodeBuffer()
    return {
      name: filename,
      blob: new SKBlob(decompressed)
    }
  })
  return files
}

/**
 * @static
 * @param {Buffer} data
 * @param {Story} story
 * @param {function} cb
 */
SKBlob.decrypt = function (data, story, cb) {
  if (!(story instanceof Story)) {
    throw new Error('SKBlob.decrypt invalid story')
  }

  if (!BufferUtils.isCompressed(data) && !BufferUtils.isMedia(data) && story) {
    data = BufferUtils.decryptStory(data, story.mediaKey, story.mediaIV)
  }

  if (BufferUtils.isCompressed(data)) {
    var files = SKBlob.decompress(data)
    return cb(null, files)
  }

  var blob = new SKBlob(data)
  return cb(blob.isMedia ? null : 'unknown blob format', blob)
}