API Docs for:
Show:

File: src/mylist/NicoMyListApi.coffee

_ = require "lodash"
Request = require "request-promise"

NicoUrl     = require "../NicoURL"
MyListMeta  = require "./MyListMeta"
MyList      = require "./MyList"

# 30秒以上経過したらトークンを取得する
FETCH_INTERVAL = 30 * 1000

# トークン抽出用パターン
tokenRegexp = /NicoAPI.token = "([0-9a-z\-]*)";/


###*
# ニコニコ動画のマイリスト操作APIのラッピングを行います。
# (参考: http://efcl.info/wiki/niconicoapi/)
#
# @TODO Manage MyList instances for support dispose.
# @class NicoMyListApi
###
module.exports =
class NicoMyListApi
    ###*
    # @private
    # @property {NicoSession} _session
    ###

    ###*
    # 認証トークン
    # @private
    # @property {Object} _token
    # @property {Number} _token.timestamp   トークンを取得した時間(ミリ秒)
    # @property {String} _token.token       マイリスト操作用トークン
    ###


    ###*
    # @constructor
    # @class NicoMyListApi
    # @param {NicoSession}      session
    ###
    constructor : (@_session) ->
        @_token =
            timestamp   : null
            token       : null


    ###*
    # マイリストを操作するための認証トークンを取得します。
    # @method fetchToken
    # @return {Promise}
    ###
    fetchToken : ->
        # 一定時間以内に取得したトークンがあればそれを返す
        if @_token.token? and (Date.now() - @_token.timestamp) < FETCH_INTERVAL
            return Promise.resolve @_token.token

        # トークン取得
        Request.get
            resolveWithFullResponse : true
            url : NicoUrl.MyList.FETCH_TOKEN
            jar : @_session.cookie
        .then (res) =>
            # データを取得したらトークンを取り出す
            token = tokenRegexp.exec res.body

            if token[1]?
                @_token.timestamp = Date.now()
                @_token.token = token[1]

                Promise.resolve token[1]
            else
                Promise.reject "NicoMyListApi: Failed to pick token."


    ###*
    # マイリストの一覧を取得します。
    # @method fetchMyListsIndex
    # @param    {boolean} withoutHome
    #   trueを指定すると"とりあえずマイリスト"を一覧から除外します。
    # @return   {Promise}
    # - resolve : (mylists: Array.<MyListItemIndex>)
    # - reject : (message: String)
    ###
    fetchOwnedListIndex : (withoutHome = false) ->
        # 受信したデータからインデックスを作成
        Request.get
            resolveWithFullResponse : true
            url   : NicoUrl.MyList.GET_GROUPS
            jar   : @_session.cookie
        .then (res) ->
            try
                result  = JSON.parse res.body
                lists   = []

                if result.status isnt "ok"
                    return Promise.reject "Failed to fetch mylist. (reason unknown)"

                # とりあえずマイリスト
                if withoutHome is false
                    lists.push MyListMeta.instance("home")

                _.each result.mylistgroup, (group) =>
                    lists.push MyListMeta.instance(group)
                    return

                return Promise.resolve lists
            catch e
                return Promise.reject "Failed to fetch mylist. (#{e.message})"


    ###*
    # MyListインスタンスを取得します。
    # @method fetchMyList
    # @param    {MyListItemIndex|number} id
    #   MyListItemIndexかマイリストIDを渡します。
    # @return   {Promise(MyList, string)}
    #   取得できればMyListオブジェクトと共にresolveされ、
    #   そうでなければエラーメッセージと共にrejectされます
    ###
    getHandlerFor : (id = "home") ->
        new Promise (resolve, reject) =>
            if id instanceof MyListMeta
                resolve(MyList.instanceById(id, @_session))
                return

            id = (id | 0) if id isnt "home"

            @fetchOwnedListIndex(false).then (metaList) =>
                meta = _.where metaList, {id}

                if meta.length is 0
                    reject "Can't find specified mylist.(#{id})"
                else
                    resolve(MyList.instanceById(meta[0], @_session))

            return

        .then (mylist) =>
            defer = Promise.defer()
            mylist.fetch().then((-> defer.resolve(mylist)), defer.reject)
            defer.promise