<commit_before>const EventEmitter = require('events')
const got = require('got')
const isDate = require('lodash/isDate')
const isNumber = require('lodash/isNumber')
const get = require('lodash/get')
const gt = require('lodash/gt')
const parseResponse = require('./parse-response')
const convertInstagramDate = require('./shared-functions/convert-instagram-date')
const InstagramError = require('./InstagramError')
const {
  INSTAGRAM_API_PROTOCOL: instagramApiProtocol,
  INSTAGRAM_API_HOST: instagramApiHost,
  INSTAGRAM_API_VERSION: instagramApiVersion
} = require('./constants')

const baseUrl = `${instagramApiProtocol}://${instagramApiHost}/${instagramApiVersion}`
const defaultOptions = {
  json: true
}

class InstagramNodeApi extends EventEmitter {
  constructor (accessToken) {
    if (!accessToken) {
      throw new Error('Invalid accessToken informed')
    }
    super()
    this.accessToken = accessToken
    this.callsCount = 0
    this.mediasCount = 0
  }

  _instagramCalled () {
    this.callsCount += 1
  }

  _mediasFounded (count) {
    this.mediasCount += count
  }

  _buildResultObject () {
    return {
      totalMedias: this.mediasCount,
      totalCalls: this.callsCount
    }
  }

  /* USERS */
  usersSelfMediaRecent (nextUrl, limitDate) {
    const url = nextUrl || `${baseUrl}/users/self/media/recent`
    const options = nextUrl ? defaultOptions : Object.assign({}, defaultOptions, {
      query: {
        access_token: this.accessToken,
        count: 33
      }
    })

    this._instagramCalled()
    got.get(url, options)
      .then(parseResponse)
      .then(([data, pagination, meta, remaining, limit]) => {
        const filteredData = limitDate
        ? data.filter(item => convertInstagramDate(item.created_time) >= limitDate)
        : data
        const continueByFilter = filteredData.length === data.length
        this._mediasFounded(filteredData.length)

        this.emit('data', filteredData, pagination, meta, remaining, limit, this._buildResultObject())

        if (pagination && pagination.next_url && continueByFilter) {
          this.usersSelfMediaRecent(pagination.next_url, limitDate)
        } else {
          this.emit('finish', data, pagination, meta, remaining, limit, this._buildResultObject())
        }
      })
      .catch((error) => {
        this.emit('err', new InstagramError(get(error, 'response.body')))
      })
  }

  usersSelf () {
    const url = `${baseUrl}/users/self`
    const options = Object.assign({}, defaultOptions, {
      query: {
        access_token: this.accessToken
      }
    })

    got.get(url, options)
      .then(parseResponse)
      .then(([data, , meta, remaining, limit]) => {
        this.emit('data', data, meta, remaining, limit)
        this.emit('finish', data, meta, remaining, limit)
      })
      .catch((error) => {
        this.emit('err', new InstagramError(get(error, 'response.body')))
      })
  }

  user (id) {
    const url = `${baseUrl}/users/${id}`
    const options = Object.assign({}, defaultOptions, {
      query: {
        access_token: this.accessToken
      }
    })

    got.get(url, options)
      .then(parseResponse)
      .then(([data, , meta, remaining, limit]) => {
        this.emit('data', data, meta, remaining, limit)
        this.emit('finish', data, meta, remaining, limit)
      })
      .catch((error) => {
        this.emit('err', new InstagramError(get(error, 'response.body')))
      })
  }

  /* TAGS */
  tagsMediaRecent (tagName, dateLimitOrLimit, limitOrNull, nextUrl) {
    const dateLimit = isDate(dateLimitOrLimit)
      ? dateLimitOrLimit
      : null
    const limit = (!isDate(dateLimitOrLimit) && isNumber(dateLimitOrLimit))
      ? dateLimitOrLimit
      : (isNumber(limitOrNull) && gt(limitOrNull, 0) ? limitOrNull : 0)

    if (!tagName) {
      this.emit('err', new Error('Invalid tagName'))
      throw new Error('Invalid tagName')
    }
    const url = nextUrl || `${baseUrl}/tags/${encodeURIComponent(tagName.toLowerCase())}/media/recent`
    const options = nextUrl ? defaultOptions : Object.assign({}, defaultOptions, {
      query: {
        access_token: this.accessToken,
        count: 33
      }
    })

    this._instagramCalled()
    got.get(url, options)
      .then(parseResponse)
      .then(([data, pagination, meta, remaining, instagramLimit]) => {
        const filteredData = dateLimit
          ? data.filter(item => convertInstagramDate(item.created_time) >= dateLimit)
          : data
        const continueByFilter = filteredData.length

        if (continueByFilter) {
          this._mediasFounded(filteredData.length)
          this.emit('data', filteredData, pagination, meta, remaining, instagramLimit, this._buildResultObject())
        }

        if (
          pagination &&
          pagination.next_url &&
          (limit === 0 || this.mediasCount < limit) &&
          continueByFilter &&
          (dateLimit || limit > 0)
        ) {
          this.tagsMediaRecent(tagName, dateLimit, limit, pagination.next_url)
        } else {
          this.emit('finish', filteredData, pagination, meta, remaining, instagramLimit, this._buildResultObject())
        }
      })
      .catch((error) => {
        this.emit('err', new InstagramError(get(error, 'response.body')))
      })
  }
}

module.exports = InstagramNodeApi
<commit_msg>:construction: Add event to get specific user medias<commit_after>const EventEmitter = require('events')
const got = require('got')
const isDate = require('lodash/isDate')
const isNumber = require('lodash/isNumber')
const get = require('lodash/get')
const gt = require('lodash/gt')
const parseResponse = require('./parse-response')
const convertInstagramDate = require('./shared-functions/convert-instagram-date')
const InstagramError = require('./InstagramError')
const {
  INSTAGRAM_API_PROTOCOL: instagramApiProtocol,
  INSTAGRAM_API_HOST: instagramApiHost,
  INSTAGRAM_API_VERSION: instagramApiVersion
} = require('./constants')

const baseUrl = `${instagramApiProtocol}://${instagramApiHost}/${instagramApiVersion}`
const defaultOptions = {
  json: true
}

class InstagramNodeApi extends EventEmitter {
  constructor (accessToken) {
    if (!accessToken) {
      throw new Error('Invalid accessToken informed')
    }
    super()
    this.accessToken = accessToken
    this.callsCount = 0
    this.mediasCount = 0
  }

  _instagramCalled () {
    this.callsCount += 1
  }

  _mediasFounded (count) {
    this.mediasCount += count
  }

  _buildResultObject () {
    return {
      totalMedias: this.mediasCount,
      totalCalls: this.callsCount
    }
  }

  /* USERS */
  usersMediaRecent (idUser, nextUrl, limitDate) {
    const url = nextUrl || `${baseUrl}/users/${idUser}/media/recent`
    const options = nextUrl ? defaultOptions : Object.assign({}, defaultOptions, {
      query: {
        access_token: this.accessToken,
        count: 33
      }
    })

    this._instagramCalled()
    got.get(url, options)
      .then(parseResponse)
      .then(([data, pagination, meta, remaining, limit]) => {
        const filteredData = limitDate
        ? data.filter(item => convertInstagramDate(item.created_time) >= limitDate)
        : data
        const continueByFilter = filteredData.length === data.length
        this._mediasFounded(filteredData.length)

        this.emit('data', filteredData, pagination, meta, remaining, limit, this._buildResultObject())

        if (pagination && pagination.next_url && continueByFilter) {
          this.usersSelfMediaRecent(pagination.next_url, limitDate)
        } else {
          this.emit('finish', data, pagination, meta, remaining, limit, this._buildResultObject())
        }
      })
      .catch((error) => {
        this.emit('err', new InstagramError(get(error, 'response.body')))
      })
  }

  usersSelfMediaRecent (nextUrl, limitDate) {
    const url = nextUrl || `${baseUrl}/users/self/media/recent`
    const options = nextUrl ? defaultOptions : Object.assign({}, defaultOptions, {
      query: {
        access_token: this.accessToken,
        count: 33
      }
    })

    this._instagramCalled()
    got.get(url, options)
      .then(parseResponse)
      .then(([data, pagination, meta, remaining, limit]) => {
        const filteredData = limitDate
        ? data.filter(item => convertInstagramDate(item.created_time) >= limitDate)
        : data
        const continueByFilter = filteredData.length === data.length
        this._mediasFounded(filteredData.length)

        this.emit('data', filteredData, pagination, meta, remaining, limit, this._buildResultObject())

        if (pagination && pagination.next_url && continueByFilter) {
          this.usersSelfMediaRecent(pagination.next_url, limitDate)
        } else {
          this.emit('finish', data, pagination, meta, remaining, limit, this._buildResultObject())
        }
      })
      .catch((error) => {
        this.emit('err', new InstagramError(get(error, 'response.body')))
      })
  }

  usersSelf () {
    const url = `${baseUrl}/users/self`
    const options = Object.assign({}, defaultOptions, {
      query: {
        access_token: this.accessToken
      }
    })

    got.get(url, options)
      .then(parseResponse)
      .then(([data, , meta, remaining, limit]) => {
        this.emit('data', data, meta, remaining, limit)
        this.emit('finish', data, meta, remaining, limit)
      })
      .catch((error) => {
        this.emit('err', new InstagramError(get(error, 'response.body')))
      })
  }

  user (id) {
    const url = `${baseUrl}/users/${id}`
    const options = Object.assign({}, defaultOptions, {
      query: {
        access_token: this.accessToken
      }
    })

    got.get(url, options)
      .then(parseResponse)
      .then(([data, , meta, remaining, limit]) => {
        this.emit('data', data, meta, remaining, limit)
        this.emit('finish', data, meta, remaining, limit)
      })
      .catch((error) => {
        this.emit('err', new InstagramError(get(error, 'response.body')))
      })
  }

  /* TAGS */
  tagsMediaRecent (tagName, dateLimitOrLimit, limitOrNull, nextUrl) {
    const dateLimit = isDate(dateLimitOrLimit)
      ? dateLimitOrLimit
      : null
    const limit = (!isDate(dateLimitOrLimit) && isNumber(dateLimitOrLimit))
      ? dateLimitOrLimit
      : (isNumber(limitOrNull) && gt(limitOrNull, 0) ? limitOrNull : 0)

    if (!tagName) {
      this.emit('err', new Error('Invalid tagName'))
      throw new Error('Invalid tagName')
    }
    const url = nextUrl || `${baseUrl}/tags/${encodeURIComponent(tagName.toLowerCase())}/media/recent`
    const options = nextUrl ? defaultOptions : Object.assign({}, defaultOptions, {
      query: {
        access_token: this.accessToken,
        count: 33
      }
    })

    this._instagramCalled()
    got.get(url, options)
      .then(parseResponse)
      .then(([data, pagination, meta, remaining, instagramLimit]) => {
        const filteredData = dateLimit
          ? data.filter(item => convertInstagramDate(item.created_time) >= dateLimit)
          : data
        const continueByFilter = filteredData.length

        if (continueByFilter) {
          this._mediasFounded(filteredData.length)
          this.emit('data', filteredData, pagination, meta, remaining, instagramLimit, this._buildResultObject())
        }

        if (
          pagination &&
          pagination.next_url &&
          (limit === 0 || this.mediasCount < limit) &&
          continueByFilter &&
          (dateLimit || limit > 0)
        ) {
          this.tagsMediaRecent(tagName, dateLimit, limit, pagination.next_url)
        } else {
          this.emit('finish', filteredData, pagination, meta, remaining, instagramLimit, this._buildResultObject())
        }
      })
      .catch((error) => {
        this.emit('err', new InstagramError(get(error, 'response.body')))
      })
  }
}

module.exports = InstagramNodeApi

{'fraction_non_alphanumeric': 0.13390001683218314, 'fraction_numerical': 0.0020198619760983, 'mean_word_length': 2.8909626719056973, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5595253', 'n_tokens_mistral': 3553, 'n_tokens_neox': 3501, 'n_words': 699}