UNPKG

node-nicovideo-api

Version:

nicovideo api (video, live, etc..) wrapper package for node.js

395 lines (330 loc) 11.7 kB
// Generated by CoffeeScript 1.10.0 /* * ニコニコ生放送の配信情報 * * Properties * stream: -- 放送の基礎情報 * liveId: string -- 放送ID * title: string -- 放送タイトル * description: string -- 放送の説明 * * watchCount: number -- 視聴数 * commentCount: number -- コメント数 * * baseTime: Date -- 生放送の時間の関わる計算の"元になる時間" * startTime: Date -- 放送の開始時刻 * openTime: Date -- 放送の開場時間 * endTime: Date -- 放送の終了時刻(放送中であれば終了予定時刻) * * isOfficial: boolean -- 公式配信か * isNsen: boolean -- Nsenのチャンネルか * nsenType: string -- Nsenのチャンネル種別("nsen/***"の***の部分) * * contents: Array<Object> * id: string -- メイン画面かサブ画面か * startTime: number -- 再生開始時間 * disableAudio: boolean -- 音声が無効にされているか * disableVideo: boolean -- 映像が無効にされているか * duration: number|null -- 再生されているコンテンツの長さ(秒数) * title: string|null -- 再生されているコンテンツのタイトル * content: string -- 再生されているコンテンツのアドレス(動画の場合は"smile:動画ID") * * owner: -- 配信者の情報 * userId: number -- ユーザーID * name: string -- ユーザー名 * * user: -- 自分自身の情報 * id: number -- ユーザーID * name: string -- ユーザー名 * isPremium: boolean -- プレミアムアカウントか * * rtmp: -- 配信に関する情報。詳細不明 * isFms: boolean * port: number * url: string * ticket: string * * comment: -- コメントサーバーの情報 * addr: string -- サーバーアドレス * port: number -- サーバーポート * thread: number -- この放送と対応するスレッドID * * @class NicoLiveInfo */ (function() { var APIEndpoints, Cheerio, CommentProvider, Emitter, NicoException, NicoLiveInfo, NicoURL, Request, _, __, sprintf, extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, hasProp = {}.hasOwnProperty; _ = require("lodash"); __ = require("lodash-deep"); Cheerio = require("cheerio"); Request = require("request-promise"); sprintf = require("sprintf").sprintf; APIEndpoints = require("../APIEndpoints"); NicoURL = require("../NicoURL"); NicoException = require("../NicoException"); Emitter = require("../Emitter"); CommentProvider = require("./CommentProvider"); module.exports = NicoLiveInfo = (function(superClass) { extend(NicoLiveInfo, superClass); /** * @propery {Object} */ NicoLiveInfo.defaults = { stream: { liveId: null, title: null, description: null, watchCount: -1, commentCount: -1, baseTime: null, openTime: null, startTime: null, endTime: null, isOfficial: false, isNsen: false, nsenType: null, contents: {} }, owner: { userId: -1, name: null }, user: { id: -1, name: null, isPremium: null }, rtmp: { isFms: null, port: null, url: null, ticket: null }, comment: { addr: null, port: -1, thread: null }, _hasError: true }; /** * @static * @return {Promise} */ NicoLiveInfo.instanceFor = function(liveId, session) { var live; if (typeof liveId !== "string" || liveId === "") { throw new TypeError("liveId must bea string"); } live = new NicoLiveInfo(liveId, session); return live.fetch().then(function() { return Promise.resolve(live); }); }; /** * マイリストが最新の内容に更新された時に発火します * @event MyList#did-refresh * @property {NicoLiveInfo} live */ /** * @private * @property {CommentProvider} _commentProvider */ NicoLiveInfo.prototype._commentProvider = null; /** * @private * @property {NicoSession} _session */ NicoLiveInfo.prototype._session = null; /** * @private * @property {Object} _attr */ NicoLiveInfo.prototype._attr = null; /** * @property {String} id */ /** * @param {NicoSession} session 認証チケット * @param {string} liveId 放送ID */ function NicoLiveInfo(liveId, _session) { this._session = _session; NicoLiveInfo.__super__.constructor.apply(this, arguments); Object.defineProperties(this, { id: { value: liveId } }); } /** * 公式放送か調べます。 * @return {boolean} */ NicoLiveInfo.prototype.isOfficialLive = function() { return !!this.get("stream").isOfficial; }; /** * Nsenのチャンネルか調べます。 * @return {boolean} */ NicoLiveInfo.prototype.isNsenLive = function() { return !!this.get("stream").isNsen; }; /** * 放送が終了しているか調べます。 * @return {boolean} */ NicoLiveInfo.prototype.isEnded = function() { return this.get("isEnded") === true; }; /** * @param {String} path */ NicoLiveInfo.prototype.get = function(path) { return __.deepGet(this._attr, path); }; /** * この放送に対応するCommentProviderオブジェクトを取得します。 * @param {Object} options 接続設定 * @param {Number} [options.firstGetComments] 接続時に取得するコメント数 * @param {Number} [options.timeoutMs] タイムアウトまでのミリ秒 * @param {Boolean} [options.connect=true] trueを指定するとコネクション確立後にresolveします * @return {Promise} */ NicoLiveInfo.prototype.commentProvider = function(options) { if (options == null) { options = {}; } _.defaults(options, { connect: false }); if (this._commentProvider != null) { return Promise.resolve(this._commentProvider); } return CommentProvider.instanceFor(this, options).then((function(_this) { return function(provider) { _this._commentProvider = provider; provider.onDidEndLive(_this._didEndLive.bind(_this)); if (options.connect) { return provider.connect(options); } else { return Promise.resolve(provider); } }; })(this)); }; /** * APIから取得した情報をパースします。 * @private * @param {String} res API受信結果 */ NicoLiveInfo.prototype.parse = function(res) { var $ms, $res, $root, $rtmp, $stream, $user, errorCode, props; $res = Cheerio.load(res); $root = $res(":root"); $stream = $res("stream"); $user = $res("user"); $rtmp = $res("rtmp"); $ms = $res("ms"); props = null; if ($root.attr("status") !== "ok") { errorCode = $res("error code").text(); throw new NicoException({ message: "Failed to parse live info (" + errorCode + ")", code: errorCode, response: res }); } props = { stream: { liveId: $stream.find("id").text(), title: $stream.find("title").text(), description: $stream.find("description").text(), watchCount: $stream.find("watch_count").text() | 0, commentCount: $stream.find("comment_count") | 0, baseTime: new Date(($stream.find("base_time").text() | 0) * 1000), openTime: new Date(($stream.find("open_time").text() | 0) * 1000), startTime: new Date(($stream.find("start_time").text() | 0) * 1000), endTime: new Date(($stream.find("end_time") | 0) * 1000), isOfficial: $stream.find("provider_type").text() === "official", isNsen: $res("ns").length > 0, nsenType: $res("ns nstype").text() || null, contents: _.map($stream.find("contents_list contents"), function(el) { var $content, ref, ref1; $content = Cheerio(el); return { id: $content.attr("id"), startTime: new Date(($content.attr("start_time") | 0) * 1000), disableAudio: ($content.attr("disableAudio") | 0) === 1, disableVideo: ($content.attr("disableVideo") | 0) === 1, duration: (ref = $content.attr("duration") | 0) != null ? ref : null, title: (ref1 = $content.attr("title")) != null ? ref1 : null, content: $content.text() }; }) }, owner: { userId: $stream.find("owner_id").text() | 0, name: $stream.find("owner_name").text() }, user: { id: $user.find("user_id").text() | 0, name: $user.find("nickname").text(), isPremium: $user.find("is_premium").text() === "1" }, rtmp: { isFms: $rtmp.attr("is_fms") === "1", port: $rtmp.attr("rtmpt_port") | 0, url: $rtmp.find("url").text(), ticket: $rtmp.find("ticket").text() }, comment: { addr: $ms.find("addr").text(), port: $ms.find("port").text() | 0, thread: $ms.find("thread").text() | 0 }, _hasError: $res("getplayerstatus").attr("status") !== "ok" }; return props; }; /** * 番組情報を最新の状態に同期します。 * @return {Promise} */ NicoLiveInfo.prototype.fetch = function() { return APIEndpoints.live.getPlayerStatus(this._session, { liveId: this.id }).then((function(_this) { return function(res) { if (res.statusCode === 503) { return Promise.reject(new Error(sprintf("Live[%s]: Nicovideo has in maintenance.", _this.id))); } _this._attr = _this.parse(res.body); _this.emit("did-refresh", _this); return Promise.resolve(); }; })(this)); }; /** * 現在のインスタンスおよび、関連するオブジェクトを破棄し、利用不能にします。 */ NicoLiveInfo.prototype.dispose = function() { var ref; if ((ref = this._commentProvider) != null) { ref.dispose(); } this._commentProvider = null; delete NicoLiveInfo._cache[this.id]; return NicoLiveInfo.__super__.dispose.apply(this, arguments); }; NicoLiveInfo.prototype._didEndLive = function() { this._attr.isEnded = true; }; NicoLiveInfo.prototype.onDidRefresh = function(listener) { return this.on("did-refresh", listener); }; return NicoLiveInfo; })(Emitter); }).call(this);