API Docs for:
Show:

File: src/video/NicoVideoInfo.coffee

_  = require "lodash"
__ = require "lodash-deep"

Request = require "request-promise"
cheerio = require "cheerio"
{sprintf} = require("sprintf")
deepFreeze = require "deep-freeze"
Ent = require "ent"

APIEndpoints = require "../APIEndpoints"
NicoException = require "../NicoException"


###*
# ニコニコ動画APIの動画情報モデルクラス
#
# Properties
#   getメソッドで第1階層まで取得できます。
#   Example: NicoVideoInfo.get("user").id
#
#
# @class NicoVideoInfo
# @extends EventEmitter2
###
module.exports =
class NicoVideoInfo
    @fetch : (movieId, session) ->
        defer = Promise.defer()
        return defer.reject "Fetch failed. Movie id not specified." unless movieId?

        # getThumbInfoの結果を取得
        APIEndpoints.video.getMovieInfo(session, {movieId})
        .then (res) ->
            if res.statusCode is 503
                defer.reject("Nicovideo has in maintenance.")

            info = new NicoVideoInfo(movieId)
            info._attr = deepFreeze(NicoVideoInfo.parseResponse(res.body))

            defer.resolve(info)

        defer.promise

    ###*
    # @private
    # @param {String}   resBody     getThumbInfoAPIから取得したXML
    # @return {Object}
    ###
    @parseResponse : (resBody) ->
        $res = cheerio.load resBody

        if $res(":root").attr("status") isnt "ok"
            errorMessage = $res("error description").text()
            throw new NicoException
                message : "Failed to fetch movie info (#{errorMessage})"
                code    : $res "error code"

        $resThumb = $res "thumb"

        # 動画の秒単位の長さを出しておく
        length = do (length) ->
            length = $resThumb.find("length").text().split(":")
            s = length.pop() | 0
            m = length.pop() | 0
            h = length.pop() | 0
            return s + (m * 60) + (h * 3600)

        {
            id          : $resThumb.find("video_id").text()
            title       : Ent.decode($resThumb.find("title").text())
            description : $resThumb.find("description").text()
            length      : length    # 秒数

            movieType   : $resThumb.find("movie_type").text()# "flv"とか
            thumbnail   : $resThumb.find("thumbnail_url").text()
            isDeleted   : false

            count       :
                view        : $resThumb.find("view_counter").text() | 0
                comments    : $resThumb.find("comment_num").text() | 0
                mylist      : $resThumb.find("mylist_counter").text() | 0

            tags        : do ->
                tagList = []

                for tags in $resThumb.find("tags")
                    $tags = cheerio tags
                    domain = $tags.attr("domain")

                    for tag in $tags.find("tag")
                        $tag = cheerio tag
                        tagList.push {
                            name        : $tag.text()
                            isCategory  : $tag.attr("category") is "1"
                            isLocked    : $tag.attr("lock") is "1"
                            domain      : domain
                        }

                tagList

            user        :
                id          : $resThumb.find("user_id").text() | 0
                name        : $resThumb.find("user_nickname").text()
                icon        : $resThumb.find("user_icon_url").text()
        }


    @defaults    :
        title           : null
        description     : null
        length          : null      # 秒数
        movieType       : null      # "flv", "mp4"
        thumbnail       : null
        isDeleted       : false
        count           :
            view            : -1
            comments        : -1
            mylist          : -1

        tags            : []        # {name:string, isCategory:boolean, isLocked:boolean}
        user            :
            id              :  -1
            name            : null
            icon            : null  # URL

    ###*
    # @property id
    # @type String
    ###

    ###*
    # @property {Object}        attributes
    # @property {String}        attributes.id           動画ID
    # @property {String}        attributes.title        動画タイトル
    # @property {String}        attributes.description  動画説明文
    # @property {Number}        attributes.length       動画の長さ(秒)
    # @property {String}        attributes.movieType    動画ファイルの形式(mp4, flv, swf)
    # @property {String}        attributes.thumbnail    サムネイル画像のURL
    # @property {Boolean}       attributes.isDeleted    削除されているか(現在、常にfalse)
    # @property {Object}        attributes.stats        統計情報
    # @property {Number}        attributes.stats.view           再生数
    # @property {Object}        attributes.stats.comments       コメント数
    # @property {Object}        attributes.stats.mylist         マイリスト数
    # @property {Array<Object>} attributes.tags         タグ情報
    # @property {String}        attributes.tags[n].name         タグ名
    # @property {Boolean}       attributes.tags[n].isCategory   カテゴリタグか
    # @property {String}        attributes.tags[n].isLocked     ロックされているか
    # @property {String}        attributes.tags[n].domain       どの国のタグか(日本="jp")
    # @property {Object}        attributes.user         投稿者情報
    # @property {Number}        attributes.user.id              ユーザーID
    # @property {String}        attributes.user.name            ユーザー名
    # @property {String}        attributes.user.icon            ユーザーアイコンのURL
    ###
    _attr : {}

    ###*
    # @class NicoVideoInfo
    # @constructor
    # @param {String}       movieId     動画ID
    # @param {NicoSession} _session     セッション
    ###
    constructor     : (movieId, @_session) ->
        # 指定された動画の動画情報インスタンスがキャッシュされていればそれを返す
        # キャッシュに対応する動画情報インスタンスがなければ、新規作成してキャッシュ
        # return VideoInfo._cache[movieId] if VideoInfo._cache[movieId]?

        # @_attr = _.cloneDeep(NicoVideoInfo.defaults)

        Object.defineProperties @,
            id :
                value : movieId

    ###*
    # 動画が削除されているか調べます。
    # @return {Boolean}
    ###
    isDeleted       : ->
      return @get "isDeleted"


    ###*
    # 属性を取得します。
    # @param {String}       path        属性名(Ex. "id", "title", "user.id")
    ###
    get             : (path) ->
        return __.deepGet @_attr, path