🏠 Home 

WatchItLater

動画を見る前にマイリストに登録したいGreasemonkey (Chrome/Fx用)


Install this script?
// ==UserScript==
// @name           WatchItLater
// @namespace      https://github.com/segabito/
// @description    動画を見る前にマイリストに登録したいGreasemonkey (Chrome/Fx用)
// @include        http://www.nicovideo.jp/*
// @include        http://i.nicovideo.jp/*
// @include        http://ch.nicovideo.jp/*
// @include        http://ext.nicovideo.jp/thumb/*
// @include        http://api.ce.nicovideo.jp/api/v1/system.unixtime?
// @exclude        http://ads*.nicovideo.jp/*
// @exclude        http://live*.nicovideo.jp/*
// @exclude        http://dic.nicovideo.jp/*
// @exclude        http://www.upload.nicovideo.jp/*
// @exclude        http://upload.nicovideo.jp/*
// @exclude        http://ch.nicovideo.jp/tool/*
// @exclude        http://flapi.nicovideo.jp/*
// @match          http://www.nicovideo.jp/*
// @match          http://ch.nicovideo.jp/*
// @match          http://i.nicovideo.jp/*
// @match          http://api.ce.nicovideo.jp/api/v1/system.unixtime?
// @match          http://*.nicovideo.jp/*
// @match          http://ext.nicovideo.jp/*
// @match          http://search.nicovideo.jp/*
// @grant          none
// @version        1.160320
// ==/UserScript==
(function() {
var isNativeGM = false;
var monkey =
(function(isNativeGM) {
var w;
try { w = unsafeWindow || window; } catch (e) { w = window;}
var document = w.document;
var require = (function() {
var require = w.require || function() {};
if (!require.defined) {
require.defined = function() { return false; };
}
return require;
})();
var $ = require.defined('jquery') ? w.require('jquery') : w.jQuery;
var _ = require.defined('lodash') ? w.require('lodash') : w._;
var advice = require.defined('advice') ? w.require('advice') : {after: function() {}, before: function() {}};
var jQuery = $;
var WatchApp   = require.defined('WatchApp')   ? require('WatchApp')   : w.WatchApp;
var PlayerApp  = require.defined('PlayerApp')  ? require('PlayerApp')  : w.PlayerApp;
var WatchJsApi = require.defined('WatchJsApi') ? require('WatchJsApi') : w.WatchJsApi;
var conf = {
autoBrowserFull: false, // 再生開始時に自動全画面化
disableAutoBrowserFullIfNicowari: false, // ユーザーニコ割があるときは自動全画面化しない
autoNotFull: true, // 再生完了時にフルスクリーン解除(原宿と同じにする)
autoTagPin: false,
topPager: true, // 検索ボックスのページャを上にする
hideLeftIchiba: false,
autoClosePlaylistInFull: true, // 全画面時にプレイリストを自動で閉じる
autoOpenSearch: false, // 再生開始時に自動検索画面
autoScrollToPlayer: true, // プレイヤー位置に自動スクロール(自動全画面化オフ時)
hideNewsInFull: true, // 全画面時にニュースを閉じる
wideCommentPanel: false, // コメントパネルをワイドにする
removeLeftPanel: true, // 左パネルを消滅させる
leftPanelJack: false, // 左パネルに動画情報を表示
rightPanelJack: true, // 右パネルに動画情報を表示
headerViewCounter: false, // ヘッダに再生数コメント数を表示
popupViewCounter: 'full', // 動画切り替わり時にポップアップで再生数を表示
ignoreJumpCommand: false, // @ジャンプ無効化
nicoSSeekCount: -1, // @ジャンプによるシーク(ループなど)を許可する回数 -1=無限 0以上はその回数だけ許可
doubleClickScroll: true, // 空白部分ををダブルクリックで動画の位置にスクロールする
hidePlaylist: true, // プレイリストを閉じる
hidePlaylistInVideoExplorer: true, // 動画選択画面でプレイリストを閉じる
hidariue: false, // てれびちゃんメニュー内に、原宿以前のランダム画像復活
videoExplorerHack: true, // 検索画面を乗っ取る
squareThumbnail: true, // 検索画面のサムネを4:3にする
enableFavTags: false, // 動画検索画面にお気に入りタグを表示
enableFavMylists: false, // 動画検索画面にお気に入りマイリストを表示
searchPageItemCount: 50, // 検索モードの1ページあたりの表示数
enableMylistDeleteButton: false, // 動画検索画面で、自分のマイリストから消すボタンを追加する
enableHoverPopup: true, // 動画リンクのマイリストポップアップを有効にする
enableAutoTagContainerHeight: true, // タグが2行以内なら自動で高さ調節(ピン留め時のみ
autoSmallScreenSearch: false, // ポップアップからのタグ検索でもプレイヤーを小さくする
enableNewsHistory: false, // ニコニコニュースの履歴を保持する
defaultSearchOption: '', // 検索時のデフォルトオプション
autoPlayIfWindowActive: 'no', // 'yes' = ウィンドウがアクティブの時だけ自動再生する
autoPlay2ndVideo: false, // 2本目以降の動画だけ自動再生
enableYukkuriPlayButton: false, // スロー再生ボタンを表示する
noNicoru: false, // ニコるボタンをなくす
enoubleTouchPanel: false, // タッチパネルへの対応を有効にする
mouseClickWheelVolume: 0, // マウスボタン+ホイールで音量調整を有効にする 1 = 左ボタン 2 = 右ボタン
enableQTouch: false, // タッチパネルモード有効
commentVisibility: 'visible', // 'visible', 'hidden', 'lastState'
lastCommentVisibility: 'visible',
controllerVisibilityInFull: '', // 全画面時に操作パネルとコメント入力欄を出す設定
enableTrueBrowserFull: false, // フチなし全画面モードにする (Chromeは画面ダブルクリックで切り替え可能)
enableSharedNgSetting: false, //
hideNicoNews: false, // ニコニコニュースを消す
hashPlaylistMode: 0,    // location.hashにプレイリストを保持 0 =無効 1=連続再生時 2=常時
storagePlaylistMode: '', // localStorageにプレイリストを保持
compactVideoInfo: true, //
hoverMenuDelay: 0.4, // リンクをホバーした時のメニューが出るまでの時間(秒)
enableFullScreenMenu: true, // 全画面時にホイールでメニューを出す
enableHeatMap: false, //
heatMapDisplayMode: 'hover', // 'always' 'hover'
replacePopupMarquee: true, //
enableRelatedTag: true, // 関連タグを表示するかどうか
//      playerTabAutoOpenNicommend: 'enable', // 終了時にニコメンドを自動で開くかどうか 'enable' 'auto' 'disable'
autoPauseInvisibleInput: true, //
customPlayerSize: '', //
removeCommentPanelHoverEvent: false, //
disableVideoExplorer: false, //
disableTagReload: false, //
disableHorizontalScroll: false, // 横スクロールバーを出なくする
hideCommentPanelSocialButtons: false, // コメントパネル下のソーシャルボタンを隠す
mylistPanelPosition: '',
enableDescriptionThumbnail: true, // 説明文の動画リンクにサムネイルとタイトル表示
fullscreenMenuLevel: 0, // フルスクリーン時のメニュー表示
enableLocalMylistCache: true,
rankingCategory_g_ent2_Close:     true,
rankingCategory_g_life2_Close:    true,
rankingCategory_g_tech_Close:     true,
rankingCategory_g_culture2_Close: true,
rankingCategory_g_other_Close:    true,
searchEngine:              'sugoi', // 'normal' 'sugoi'
searchStartTimeRange:      '', //
searchLengthSecondsRange:  '', //
searchCommentCountRange:   '', //
searchMusicDlFilter:       false, //
hideVideoExplorerExpand: true, // 「動画をもっと見る」ボタンを小さくする
//      nicommendVisibility: 'visible', // ニコメンドの表示 'visible', 'underIchiba', 'hidden'
ichibaVisibility:    'visible', // 市場の表示 '',   'visible', 'hidden'
reviewVisibility:    'visible', // レビューの表示   'visible', 'hidden'
bottomContentsVisibility: 'hidden', // 動画下のコンテンツ表示表示非表示
hideMenuInFull: 'hide', // 全画面時にマイリストメニューを隠す '', 'hide' = 目立たなくする, 'hideAll' = 完全非表示
flatDesignMode: '',  // 'on' グラデーションや角丸をなくす。 7/25からQwatchがフラットデザインになったので不要になった
playerBgStyle: '',  // ↑ の後継パラメータ 'gray' 'white' ''
shortcutTogglePlay:         {char: 'P', shift: false, ctrl: false, alt: true,  enable: false}, // 停止/再生
shortcutDefMylist:          {char: 'M', shift: true,  ctrl: false, alt: false, enable: false}, // とりマイ登録のショートカット
shortcutMylist:             {char: 'M', shift: false, ctrl: true , alt: false, enable: false}, // マイリスト登録のショートカット
shortcutOpenSearch:         {char: 'S', shift: true,  ctrl: false, alt: false, enable: false}, // 検索オープンのショートカット
shortcutOpenDefMylist:      {char: 'D', shift: true,  ctrl: false, alt: false, enable: false}, // とりマイオープンのショートカット
shortcutOpenRecommend:      {char: 'R', shift: true,  ctrl: false, alt: false, enable: false}, // 関連動画(オススメ)を開くショートカット
shortcutCommentVisibility:  {char: 'V', shift: true,  ctrl: false, alt: false, enable: false}, // コメント表示ON/OFFのショートカット
shortcutScrollToNicoPlayer: {char: 'P', shift: true,  ctrl: false, alt: false, enable: false}, // プレイヤーまでスクロールのショートカット
shortcutShowOtherVideo:     {char: 'U', shift: true,  ctrl: false, alt: false, enable: false}, // 投稿者の関連動画表示のショートカット
shortcutMute:               {char: 'T', shift: true,  ctrl: false, alt: false, enable: false}, // 音量ミュートのショートカット
shortcutDeepenedComment:    {char: 'B', shift: true,  ctrl: false, alt: false, enable: false}, // コメント背面表示
shortcutToggleStageVideo:   {char: 'H', shift: true,  ctrl: false, alt: false, enable: false}, // ハードウェアアクセラレーション(StageVideo)のショートカット
shortcutInvisibleInput:     {char: 'C', shift: false, ctrl: false,  alt: true, enable: true}, // 停止/再生
initializeImmediately: true, // 動画のロードを待たずに初期化する
watchCounter: 0, // お前は今までに見た動画の数を覚えているのか?をカウントする
forceEnableStageVideo: false,
forceExpandStageVideo: false,
enableAutoPlaybackContinue: false, // 一定時間操作しなくても自動再生を続行
lastLeftTab: 'videoInfo',
lastRightTab: 'w_videoInfo',
lastRightTabInExplorer: 'comment',
lastControlPanelPosition: '',
enableSortTypeMemory: true, // 検索のソート順を記憶する
searchSortType: 'n', //
searchSortOrder: 'd', // 'd'=desc 'a' = asc
fxInterval: 40, // アニメーションのフレームレート 40 = 25fps
enableGpuLayer: false, // 一部の要素でGPU描画を有効にしてみる?
debugMode: false
};
//===================================================
//===================================================
//===================================================
function addStyle(styles, id) {
var elm = document.createElement('style');
window.setTimeout(function() {
elm.type = 'text/css';
if (id) { elm.id = id; }
var text = styles.toString();
text = document.createTextNode(text);
elm.appendChild(text);
var head = document.getElementsByTagName('head');
head = head[0];
head.appendChild(elm);
}, 0);
return elm;
}
if (!isNativeGM) {
this.httpRequest = function(options) {
try {
var req = new XMLHttpRequest();
var method = options.method || 'GET';
req.onreadystatechange = function() {
if (req.readyState === 4) {
if (typeof options.onload === "function") options.onload(req);
}
};
req.open(method, options.url, true);
if (options.headers) {
for (var h in options.headers) {
req.setRequestHeader(h, options.headers[h]);
}
}
req.send(options.data || null);
} catch (e) {
if (conf.debugMode) console.log(e);
}
};
}
(function() { // 各ページ共通
var __css__ = (function() {/*
.tagItemsPopup {
background: #eef;
}
.popupMenu {
position: absolute;
min-width: 200px;
font-Size: 12pt;
z-index: 2000000;
box-shadow: 2px 2px 2px #888;
}
.popupMenu ul,   .popupMenu ul li {
position: relative;
list-style-type: none;
margin: 0; padding: 0;
white-space: nowrap;
}
.tagItemsPopup .icon{
width: 17px;
height: 15px;
}
.tagItemsPopup .nicodic, .tagItemsPopup .newsearch {
margin: 1px 4px 1px 1px;
}
.tagItemsPopup .nicodic:hover, .tagItemsPopup .newsearch:hover {
margin: 0px 3px 0px 0px;
border: 1px outset;
}
.mylistListPopup {
position:absolute;
background: #fff;
overflow: visible;
padding: 8px;
border: 1px outset #333;
transition: opacity 0.3s ease;
}
.mylistListPopup.popupMenu ul li {
position: relative;
margin: 2px 8px;
overflow-y: visible;
}
.mylistListPopup:not(.show) {
left: -9999px;
top: -9999px;
opacity: 0;
}
.mylistListPopup.show {
opacity: 1;
}
.mylistListPopup .listInner {
-webkit-column-width: auto; -moz-column-width: auto;
-webkit-column-count: 1 !important; {* Chromeだけバグるので *}
}
.mylistListPopup .icon {
display: inline-block;
width: 18px;
height: 14px;
margin: -4px 4px 0 0;
vertical-align: middle;
margin-right: 15px;
background: url("http://uni.res.nimg.jp/img/zero_my/icon_folder_default.png") no-repeat scroll 0 0 transparent;
transform: scale(1.5); -webkit-transform: scale(1.5);
transform-origin: 0 0 0; -webkit-transform-origin: 0 0 0;
transition: transform 0.1s ease, box-shadow 0.1s ease;
-webkit-transition: -webkit-transform 0.1s ease, box-shadow 0.1s ease;
cursor: pointer;
}
.mylistListPopup .icon:hover {
background-color: #ff9;
transform: scale(2); -webkit-transform: scale(2);
}
.mylistListPopup .icon::after {
content: '開く';
position: absolute;
bottom: 0px;
right: 12px;
padding: 2px;
opacity: 0;
transform: scale(0.5); -webkit-transform: scale(0.5);
z-index: -1;
}
.mylistListPopup .icon:hover::after {
{*box-shadow: 2px 2px 2px #888;*}
background: #fff;
z-index: 100;
opacity: 1;
}
.mylistListPopup .deflist .icon { background-position: 0 -253px; }
.mylistListPopup .folder1 .icon { background-position: 0 -23px;}
.mylistListPopup .folder2 .icon { background-position: 0 -46px;}
.mylistListPopup .folder3 .icon { background-position: 0 -69px;}
.mylistListPopup .folder4 .icon { background-position: 0 -92px;}
.mylistListPopup .folder5 .icon { background-position: 0 -115px;}
.mylistListPopup .folder6 .icon { background-position: 0 -138px;}
.mylistListPopup .folder7 .icon { background-position: 0 -161px;}
.mylistListPopup .folder8 .icon { background-position: 0 -184px;}
.mylistListPopup .folder9 .icon { background-position: 0 -207px;}
.mylistListPopup .name {
display: inline-block;
vertical-align: middle;
font-size: 110%;
color: #666;
text-derocation: none !important;
}
.mylistListPopup .name:hover {
color: #000;
background-color: #ff9;
}
.mylistListPopup .name::after {
content: ' に登録';
font-size: 75%;
color: #fff;
}
.mylistListPopup .name.exist::after {
content: ' に登録済';
color: #933;
}
.mylistListPopup .name:hover::after {
color: #666;
}
{* マイリスト登録パネル *}
.mylistPopupPanel {
height: 24px;
z-index: 10000;
{*border: 1px solid silver;
border-radius: 3px; *}
padding: 0;
margin: 0;
overflow: hidden;
display: inline-block;
background: #eee;
}
.mylistPopupPanel.fixed {
position: fixed; right: 0; bottom: 0;
transition: right 0.1s ease-out;
}
.mylistPopupPanel.fixed.left {
right: auto;
left: 0;
}
.mylistPopupPanel.fixed.top {
bottom: auto;
top: 0;
}
.mylistPopupPanel.fixed>* {
transition: opacity 0.1s ease-out;
}
.mylistPopupPanel>*>* {
transition: background 0.5s ease 0.5s, color 0.5s ease 0.5s;
}
.full_with_browser .mylistPopupPanel,   .mylistPopupPanel.black {
background: #000; border: 0;
}
body.full_with_browser .mylistPopupPanel *,body .mylistPopupPanel.black.fixed * {
background: #000; color: #888; border-color: #333;
}
.full_with_browser                  .mylistPopupPanel.hideAllInFull{
display: none;
}
.full_with_browser.fullWithPlaylist .mylistPopupPanel.hideInFull,
.full_with_browser.fullWithPlaylist .mylistPopupPanel.hideAllInFull {
display: block;
}
.full_with_browser .mylistPopupPanel.hideInFull.fixed:not(:hover) {
right: -100px;
transition: right 0.8s ease-in-out 0.5s;
}
.full_with_browser .mylistPopupPanel.hideInFull.fixed.left:not(:hover) {
left: -100px; right: auto;
transition: left 0.8s ease-in-out 0.5s;
}
.full_with_browser .mylistPopupPanel.hideInFull:not(:hover)>*{
opacity: 0;
transition: opacity 0.3s ease-out 1s;
}
.mylistPopupPanel.w_touch {
height: 40px;
}
iframe.popup {
position: absolute;
}
{* マウスホバーで出るほうのマイリスト登録パネル *}
.mylistPopupPanel.popup {
position: absolute;
z-index: 1000000;
box-shadow: 2px 2px 2px #888;
}
{* マイリスト登録パネルの中の各要素 *}
.mylistPopupPanel .mylistSelect {
width: 64px;
margin: 0;
padding: 0;
font-size: 80%;
white-space: nowrap;
{*background: #eee;*}
border: 1px solid silver;
}
.mylistSelect:focus {
border-style: outset;
}
{* 誤操作を減らすため、とりマイの時だけスタイルを変える用 *}
.mylistPopupPanel.w_touch button {
padding: 8px 18px;
}
.mylistPopupPanel.w_touch .mylistSelect {
font-size: 170%; width: 130px; border: none;
}
.mylistPopupPanel.w_touch .mylistSelect:focus {
border: 1px dotted;
}
.mylistPopupPanel.deflistSelected button {
}
.mylistPopupPanel.mylistSelected  button {
color: #ccf;
}
.mylistPopupPanel button {
margin: 0;
font-weight: bolder;
cursor: pointer;
}
.mylistPopupPanel button:active, #outline .playlistToggle:active, #outline .openVideoExplorer:active, #content .openConfButton:active {
border:1px inset !important
}
.mylistPopupPanel button:hover, #outline .playlistToggle:hover, #outline .openVideoExplorer:hover, #outline .openConfButton:hover, #yukkuriPanel .yukkuriButton:hover {
border:1px outset
}
.mylistPopupPanel .mylistAdd, .mylistPopupPanel .tagGet, #yukkuriPanel .yukkuriButton {
border:1px solid #777; cursor: pointer; font-family:arial, helvetica, sans-serif; padding: 0px 4px 0px 4px; text-shadow: -1px -1px 0 rgba(0,0,0,0.3);font-weight:bold; text-align: center; color: #eee; background-color: #888; margin: 0;
}
.mylistPopupPanel .mylistAdd:focus, .mylistPopupPanel .tagGet:focus, #yukkuriPanel .yukkuriButton:focus {
border-style: outset; color: orange;
}
.mylistPopupPanel.deflistSelected {
color: #ff9;
}
.mylistPopupPanel .deflistRemove, #yukkuriPanel .yukkuriButton.active{
border:1px solid #ebb7b7; font-family:arial, helvetica, sans-serif; padding: 0px 6px 0px 6px; text-shadow: -1px -1px 0 rgba(0,0,0,0.3);font-weight:bold; text-align: center; color: #FFFFFF; background-color: #f7e3e3;
}
.mylistPopupPanel.deflistSelected {
color: #ff9;
}
.mylistPopupPanel .deflistRemove, #yukkuriPanel .yukkuriButton.active{
border:1px solid #ebb7b7; font-family:arial, helvetica, sans-serif; padding: 0px 6px 0px 6px; text-shadow: -1px -1px 0 rgba(0,0,0,0.3); text-align: center; color: #FFFFFF; background-color: #f7e3e3;
}
.mylistPopupPanel.mylistSelected .deflistRemove {
display: none;
}
.mylistPopupPanel .closeButton{
color: #339;
padding: 0;
margin: 0;
font-size: 80%;
text-decoration: none;
}
.mylistPopupPanel .newTabLink{
padding: 0 2px; text-decoration: underline; text-shadow: -1px -1px 0px #442B2B;
}
.mylistPopupPanel.fixed .newTabLink, .mylistPopupPanel.fixed .closeButton {
display: none;
}
.w_fullScreenMenu .mylistPopupPanel.fixed { bottom: 2px; }
{* ポイントが無いときは表示しない *}
.item:not(.silver):not(.gold) .uadContainer {
display: none !important;
}
.xDomainLoaderFrame {
width: 1px;
height: 1px;
position: fixed;
top: -100px;
left: -100px;
border: 0;
overflow: hidden;
}
{* tagrepo *}
.contents-thumbnail a {
display: inline-block;
}
*/}).toString().match(/[^]*\/\*([^]*)\*\/\}$/)[1]
.replace(/\{\*/g, '/*').replace(/\*\}/g, '*/');
addStyle(__css__, 'watchItLaterCommonStyle');
})(); // end of commoncss
(function() { // watchページだけのstyle
if (!WatchJsApi) { return; }
var __css__ = (function() { /*
{* 動画タグとプレイリストのポップアップ *}
#videoTagPopupContainer {
}
#videoTagPopupContainer.w_touch {
line-height: 200%; font-size: 130%;
}
#videoTagPopupContainer.w_touch .nicodic{
margin: 4px 14px;
}
.playlistMenuPopup {
background: #666; color: white; padding: 4px 8px;
}
.playlistMenuPopup.w_touch {
line-height: 250%;
}
#playlistSaveDialog {
display: none;
}
#playlistSaveDialog.show {
display: block;
}
#playlistSaveDialog.show .shadow{
position: fixed;
top: 0; left: 0; width: 100%; height: 100%;
background: #000; opacity: 0.5;
z-index: 30000;
}
#playlistSaveDialog.show .formWindow{
position: fixed;
margin: 0 auto;
text-align: center;
width: 100%;
top: 45%;
z-index: 30001;
}
#playlistSaveDialog      .formWindow .formWindowInner{
-webkit-transition: opacity 1s ease-out;
transition: opacity 1s ease-out;
opacity: 0;
}
#playlistSaveDialog.show .formWindow .formWindowInner{
text-align: left;
opacity: 1;
margin: 0 auto;
background: #f4f4f4;
width: 500px;
padding: 8px;
border: 1px solid;
}
#playlistSaveDialog.show .formWindow .formWindowInner a{
font-weight: bolder;
}
#playlistSaveDialog.show .formWindow .formWindowInner a:hover{
text-decoration: underline; background: white;
}
#playlistSaveDialog.show .formWindow .formWindowInner label{
margin: 8px;
}
#playlistSaveDialog.show .formWindow .formWindowInner input{
}
#playlistSaveDialog.show .formWindow .formWindowInner .desc{
font-size: 80%;
}
.playlistMenuPopup ul li {
cursor: pointer;
}
.playlistMenuPopup ul li.savelist {
color: #aaa;
}
.playlistMenuPopup ul li:hover {
text-decoration: underline; background: #888;
}
#yukkuriPanel .yukkuriButton.active {
border:1px inset
}
#content .openConfButton {
border:1px solid #bbb; cursor: pointer; font-family:arial, helvetica, sans-serif; padding: 4px; text-shadow: 1px 1px 0 rgba(0,0,0,0.3); text-align: center; color: #444; background-color: #ccc; margin: 0;
}
#outline .playlistToggle, #outline .openVideoExplorer, #outline .openConfButton {
border:1px solid #444; cursor: pointer; font-family:arial, helvetica, sans-serif; padding: 0px 4px 0px 4px; box-shadow: 1px 1px 0 rgba(0,0,0,0.3); text-align: center; color: #444; background-color: #ccc; margin: 0;
height: 24px; border-radius: 0 0 8px 8px;
}
#outline .openConfButton { padding: 0 8px; letter-spacing: 4px; width: 60px; }
{* 全画面時にプレイリスト表示 *}
body.full_with_browser.fullWithPlaylist #playlist{
z-index: 100 !important;
display: block !important;
position: absolute;
bottom: 0;
}
body.full_with_browser.fullWithPlaylist .browserFullOption{
display: none !important;
}
body.full_with_browser.fullWithPlaylist #content.playlist #playerContainerWrapper {
margin-bottom: 167px !important;
}
{* 少しでも縦スクロールを減らすため、動画情報を近づける。人によっては窮屈に感じるかも *}
#outline {
margin-top: -16px;
}
#outline #feedbackLink{
}
#outline .videoEditMenuExpand{
position: absolute;right: 0;top: 26px; z-index: 1;
}
{* ヘッダに表示する再生数 *}
#videoCounter {
color: #ff9; font-size: 70%;
}
{* 右に表示する動画情報 *}
.sidePanel .sideVideoInfo, .sidePanel .sideIchibaPanel, .sidePanel .sideReviewPanel  {
padding: 0px 0px 0 0px; width: 196px; height: 100%; z-index: 10019;
position:absolute; top:0; right:0; border: 1px solid #000;
overflow-x: visible; overflow-y: auto;
}
{* 右に表示する動画情報 *}
#playerTabWrapper.sidePanel .sideVideoInfo, #playerTabWrapper.sidePanel .sideIchibaPanel, #playerTabWrapper.sidePanel .sideReviewPanel  {
padding: 0px 0px 0 0px; width: 324px; height: 100%;
position: absolute; top: 0; right:0;
}
body:not(.full_with_browser) .w_wide #playerTabWrapper .sideVideoInfo,
body:not(.full_with_browser) .w_wide #playerTabWrapper .sideIchibaPanel,
body:not(.full_with_browser) .w_wide #playerTabWrapper .sideReviewPanel,
.videoExplorer #playerTabWrapper .sideVideoInfo,
.videoExplorer #playerTabWrapper .sideIchibaPanel,
.videoExplorer #playerTabWrapper .sideReviewPanel {
width: 418px;
}
#playerTabWrapper.w_videoInfo #appliPanel, #playerTabWrapper.w_ichiba #appliPanel, #playerTabWrapper.w_review #appliPanel  {
top: -9999px;
}
.sidePanel .sideVideoInfo {
background: #f4f4f4; text-Align:   left; overflow-x: hidden; overflow-Y: auto; box-shadow: none; font-size: 90%; border: 1px solid black;
}
.sidePanel .sideIchibaPanel, .sidePanel .sideReviewPanel  {
background: #f4f4f4; text-Align: center; overflow-x: hidden; overflow-Y: auto; box-shadow: none; font-size: 90%;
}
.sidePanel .sideVideoInfo .sideVideoInfoInner {
padding: 0 4px; position: relative;
}
.sidePanel .sideVideoInfo .videoTitleContainer {
background: #ddd; text-align: center;  color: #000; margin: 6px 6px 0;
border: solid; border-width: 2px 2px 0; border-color: #888;
}
.sidePanel .sideVideoInfo .videoOwnerInfoContainer {
margin: 0 6px; border: solid; border-width: 0 2px 0; border-color: #888;
}
.sidePanel .sideVideoInfo .videoThumbnailContainer {
background: #ddd; text-align: center; color: #000; margin: 0;
}
.sidePanel .sideVideoInfo .videoThumbnailContainer img {
cursor: pointer;
}
.sidePanel .sideVideoInfo .videoTitle {
padding: 8px;
}
.sidePanel .sideVideoInfo .videoPostedAt {
color: #333;
}
.sidePanel .sideVideoInfo .videoStats{
font-size:90%;
}
.sidePanel .sideVideoInfo .videoStats li{
display: inline-block; margin: 0 2px;
}
.sidePanel .sideVideoInfo .videoStats li span{
font-weight: bolder;
}
.sidePanel .sideVideoInfo .videoStats .ranking{
display: none !important;
}
.sidePanel .sideVideoInfo .videoInfo{
background: #ddd; text-align: center; padding: 4px; margin: 0 6px 6px;
border: solid; border-width: 0 2px 2px; border-color: #888;
}
.sideVideoInfo .sideVideoInfoInner{
-webkit-transition: opacity 1s ease-out, color 3s ease-out;
transition: opacity 1s ease-out, color 3s ease-out;
opacity: 0;
}
.sideVideoInfo.show .sideVideoInfoInner{
opacity: 1;
}
.videoCount.blink {
color: #ccc;
}
.sidePanel .videoCountDiff {
position: absolute; color: white; right: 0; opacity: 0; z-index: 100; text-shadow: 1px 1px 0 orange;
}
.sidePanel .videoCountDiff.blink {
opacity: 1; color: white;
}
#siteHeader .videoCount, #siteHeader .videoCountDiff {
min-width: 32px; text-align: right; display: inline-block;
}
#siteHeader .videoCountDiff, #fullScreenToggleContainer .videoCountDiff {
position: absolute; color: yellow; opacity: 0; font-weight: bolder; text-shadow: 1px 1px 0 red;
}
#siteHeader .videoCountDiff.blink, #fullScreenToggleContainer .videoCountDiff.blink {
opacity: 1; color: yellow;
}
.videoExplorer #siteHeaderNicopoPurchase,
.videoExplorer #siteHeaderUserNickNameContainer,
.size_medium #siteHeaderNicopoPurchase,
.size_medium #siteHeaderUserNickNameContainer,
#siteHeaderNotificationPremium {
display: none !important;
}
#fullScreenToggleContainer .blink, #videoCounter .blink {
color: #000;
}
.videoCountDiff::before      {content: '+';}
.videoCountDiff.down::before {content: ''; }
#popupMarquee .videoCountDiff {display: none;}
.sidePanel .sideVideoInfo .videoDescription{
overflow-x: hidden; text-align: left;
}
.sidePanel .sideVideoInfo .videoDescriptionInner{
margin: 0 8px;
}
.sidePanel .sideVideoInfo .videoDetails{
min-width: 150px;
}
.sidePanel .sideVideoInfo .videoDetails a{
margin: auto 4px;
}
.sidePanel .sideVideoInfo .videoDetails a:visited{
color: #04618c;
}
.sidePanel .sideVideoInfo .videoDetails a.watch{
margin: auto 30px auto 4px;
display:inline-block;
}
.sideVideoInfo .userName, .sideVideoInfo .channelName{
display: block;
font-size: 120%;
cursor: pointer;
}
.sideVideoInfo .userIconContainer, .sideVideoInfo .channelIconContainer {
background: #ddd; width: 100%; text-align: center; float: none;
}
.sidePanel .userIcon, .sidePanel .channelIcon{
min-width: 128px; max-width: 150px; width: auto; height: auto; border: 0;
box-shadow: 0 0 4px #666; cursor: pointer;
}
.sideVideoInfo .descriptionThumbnail {
text-align: left; font-size: 90%; padding: 4px; background: #ddd;
min-height: 50px; margin: 4px 8px; font-weight: normal; color: black;
}
.sideVideoInfo .descriptionThumbnail p {
margin: 0 8px;
font-weight: bolder;
}
.sideVideoInfo .descriptionThumbnail .uploadAt {
font-size: 90%;
margin: 4px;
color: #333;
}
.sideVideoInfo .descriptionThumbnail .counterContainer {
text-align: center;
}
.sideVideoInfo .descriptionThumbnail .view,
.sideVideoInfo .descriptionThumbnail .comment,
.sideVideoInfo .descriptionThumbnail .mylist
{
font-size: 90%;
white-space: nowrap;
margin-right: 4px;
color: #333;
}
.sideVideoInfo .descriptionThumbnail .count {
font-weight: bolder;
}
.sideVideoInfo .descriptionThumbnail.video img{
height: 50px; cursor: pointer; float: left;
}
.sideVideoInfo .descriptionThumbnail.mylist img{
height: 40px; cursor: pointer;
}
.sideVideoInfo .descriptionThumbnail.illust img{
height: 60px; cursor: pointer;
}
.sideVideoInfo a.otherSite {
font-weight: bolder; text-decoration: underline;
}
body:not(.videoExplorer) #leftPanel.removed {
display: none; left: 0px;
}
body:not(.videoExplorer) #leftPanel.removed .sideVideoInfo {
display: none; width: 0px !important; border: none; margin: 0; padding: 0; right: auto;
}
.sideVideoInfo .userIconContainer.isUserVideoPublic .notPublic { display: none; }
.sideVideoInfo .userIconContainer                    .isPublic { display: none; }
.sideVideoInfo .userIconContainer.isUserVideoPublic  .isPublic { display: inline; }
body.videoExplorer #content.w_adjusted .sideIchibaPanel .ichiba_mainitem,
.sidePanel .sideIchibaPanel .ichiba_mainitem {
width: 180px; display:inline-block; vertical-align: top;
margin: 4px 3px; border 1px solid silver;
}
body.videoExplorer #content.w_adjusted .sideIchibaPanel .ichiba_mainitem .thumbnail span {
font-size: 60px;
}
body.videoExplorer #content.w_adjusted .sideIchibaPanel .ichiba_mainitem>div>dt {
height: 50px;position: relative;
}
body.videoExplorer #content.w_adjusted .sideIchibaPanel .ichiba_mainitem .balloonUe {
position: absolute;width: 100%;
}
body.videoExplorer #content.w_adjusted .sideIchibaPanel .ichiba_mainitem .balloonUe {
position: absolute;
}
body.videoExplorer #content.w_adjusted .sideIchibaPanel .ichiba_mainitem .balloonShita {
position: absolute;
}
.sidePanel.videoInfo, .sidePanel.ichiba{
background: none;
}
.sideVideoInfo.isFavorite .userName::after, .sideVideoInfo.isFavorite.isChannel .videoOwnerInfoContainer .channelName::after{
content: ' ★ '; color: gold; text-shadow: 1px 1px 1px black;
}
.sidePanel.videoInfo  #leftPanelContent, .sidePanel.ichiba  #leftPanelContent {
display: none;
}
.sidePanel.w_comment    #playerTabContainer,
.sidePanel.videoInfo    .sideVideoInfo,
.sidePanel.ichiba       .sideIchibaPanel,
.sidePanel.w_videoInfo  .sideVideoInfo,
.sidePanel.w_ichiba     .sideIchibaPanel,
.sidePanel.w_review     .sideReviewPanel {
display: block; z-index: 10060;
}
.sidePanel:not(.w_comment) .watchWatchContainer {
display: none;
}
#leftPanelTabContainer {
display:none; background: #666; position: absolute; right: 4px; top: -27px; list-style-type: none; padding: 4px 6px 3px 60px; height: 20px;
}
#sidePanelTabContainer {
display: none;
position: absolute; list-style-type: none;
padding: 5px 10px 0; right: -408px; top: 0; width: 350px; height: 34px;
transform: rotate(90deg);         transform-origin: 0 0 0;
-webkit-transform: rotate(90deg); -webkit-transform-origin: 0 0 0;
z-index: 1000;
}
.full_with_browser #sidePanelTabContainer {
background: #000 !important;
}
body:not(.videoExplorer):not(.full_with_browser) #sidePanelTabContainer.left {
background: #000; right: auto; left: -375px; padding: 0; height: 27px;
transform: rotate(-90deg);         transform-origin: 100% 0 0;
-webkit-transform: rotate(-90deg); -webkit-transform-origin: 100% 0 0;
}
#leftPanelTabContainer.w_touch {
top: -40px; height: 33px;
}
.sidePanel:hover #sidePanelTabContainer, .sidePanel:hover #leftPanelTabContainer {
display: block;
}
#leftPanelTabContainer .tab{
display: inline-block; cursor: pointer; background: #999; padding: 2px 4px 0px; border-width: 2px 2px 0px;
}
#leftPanelTabContainer.w_touch .tab, #sidePanelTabContainer.w_touch .tab {
padding: 8px 12px 8px;
}
#sidePanelTabContainer .tab {
background: none repeat scroll 0 0 #999999; border-width: 2px 2px 0; cursor: pointer;
display: inline-block; font-size: 13px; padding: 5px 10px 8px;
border-radius: 8px 8px 0px 0px;
}
body:not(.videoExplorer):not(.full_with_browser) #sidePanelTabContainer.left .tab {
display: inline-block; font-size: 13px; padding: 5px 10px 0px;
}
#leftPanel.videoInfo .tab.videoInfo, #leftPanel.ichiba .tab.ichiba {
background: #f4f4f4;    border-style: outset;
}
#playerTabWrapper.w_comment   .tab.comment,
#playerTabWrapper.w_videoInfo .tab.videoInfo,
#playerTabWrapper.w_ichiba    .tab.ichiba,
#playerTabWrapper.w_review    .tab.review
{
background: #dfdfdf; border-style: outset;
}
#playerTabWrapper.w_videoInfo #playerCommentPanel,
#playerTabWrapper.w_ichiba #playerCommentPanel,
#playerTabWrapper.w_review #playerCommentPanel {
{*display: none;*} top: -9999px;
}
.sidePanel.ichibaEmpty  .tab.ichiba, .sidePanel.reviewEmpty .tab.review {
color: #ccc;
}
.sideIchibaPanel .ichibaPanelInner {
margin:0; color: #666;
}
.sideIchibaPanel .ichibaPanelHeader .logo{
text-shadow: 1px 1px 1px #666; cursor: pointer; padding: 4px 0px 4px; font-size: 125%;
}
.sideIchibaPanel .ichibaPanelFooter{
text-align: center;
}
.sideIchibaPanel .ichiba_mainitem {
margin: 0 0 8px 0; background: white; border-bottom : 1px dotted #ccc;
}
.sideIchibaPanel .ichiba_mainitem a:hover{
background: #eef;
}
.sideIchibaPanel .ichiba_mainitem>div {
max-width: 266px; margin: auto; text-align: center;
}
.sideIchibaPanel .ichiba_mainitem .blomagaArticleNP {
background: url("http://ichiba.nicovideo.jp/embed/zero/img/bgMainBlomagaArticleNP.png") no-repeat scroll 0 0 transparent;
height: 170px;
margin: 0 auto;
width: 180px;
}
.sideIchibaPanel .ichiba_mainitem .blomagaLogo {
color: #FFFFFF;font-size: 9px;font-weight: bold;padding-left: 10px;padding-top: 8px;
}
.sideIchibaPanel .ichiba_mainitem .blomagaLogo span{
background: none repeat scroll 0 0 #AAAAAA;padding: 0 3px;
}
.sideIchibaPanel .ichiba_mainitem .blomagaText {
color: #666666;font-family: 'HGS明朝E','MS 明朝';font-size: 16px;height: 100px;
padding: 7px 25px 0 15px;text-align: center;white-space: normal;word-break: break-all;word-wrap: break-word;
}
.sideIchibaPanel .ichiba_mainitem .blomagaAuthor {
color: #666666; font-size: 11px;padding: 0 20px 0 10px;text-align: right;
}
.sideIchibaPanel .ichiba_mainitem .balloonUe{
bottom: 12px; display: block; max-width: 266px;
}
.sideIchibaPanel .ichiba_mainitem .balloonUe a{
background: url("/img/watch_zero/ichiba/imgMainBalloonUe.png") no-repeat scroll center top transparent;
color: #666666 !important;
display: block;
font-size: 108%;
line-height: 1.2em;
margin: 0 auto;
padding: 8px 15px 3px;
text-align: center;
text-decoration: none;
word-wrap: break-word;
}
.sideIchibaPanel .ichiba_mainitem .balloonShita{
height: 12px; bottom: 0; left: 0;
}
.sideIchibaPanel .ichiba_mainitem .balloonShita img{
vertical-align: top !important;
}
.sideIchibaPanel .ichiba_mainitem .ichibaMarquee {
display: none;
}
.sideIchibaPanel .ichiba_mainitem .thumbnail span {
font-size: 22px; color: #0066CC;
font-family: 'ヒラギノ明朝 Pro W3','Hiragino Mincho Pro','MS P明朝','MS PMincho',serif;
}
.sideIchibaPanel .ichiba_mainitem .action {
font-size: 85%;
}
.sideIchibaPanel .ichiba_mainitem .action .buy {
font-weight: bolder; color: #f60;
}
.sideIchibaPanel .ichiba_mainitem .itemname {
font-weight: bolder;
}
.sideIchibaPanel .ichiba_mainitem .maker {
font-size: 77%; margin-bottom: 2px;
}
.sideIchibaPanel .ichiba_mainitem .price {
}
.sideIchibaPanel .ichiba_mainitem .action .click {
font-weight: bolder;
}
.sideIchibaPanel .ichiba_mainitem .goIchiba {
font-size: 77%; margin: 5px 0;
}
.sideIchibaPanel .addIchiba, .sideIchibaPanel .reloadIchiba {
cursor: pointer;
}
.sideIchibaPanel .noitem {
cursor: pointer;
}
#outline .bottomAccessContainer {
position: absolute; top: 12px;
}
#outline .bottomConfButtonContainer {
position: absolute; top: 12px; right: 0px;
}
body.videoExplorer .bottomAccessContainer{
display: none;
}
#outline.under960 .bottomAccessContainer{
right: 60px;
}
.watchItLaterSettingMenu {
font-weight: bolder;
white-space: nowrap;
}
#outline .sidebar {
-webkit-transition: margin-top 0.3s ease-out;
transition:         margin-top 0.3s ease-out;
}
#outline.under960 .sidebar {
margin-top: 24px;
}
#videoHeader.menuClosed .watchItLaterMenu, #videoHeader.menuClosed .hidariue { display: none; }
#videoHeader .watchItLaterMenu {
position: absolute; width: 100px; left: -55px; top: 32px;
}
{* タイトルクリックでヘッダが開閉できるのをわかりやすく *}
.videoDetailToggleButton:hover {
text-decoration: underline;
}
.videoDetailToggleButton:hover::after {
content: '▼';
position: absolute;
width: 32px;
height: 20px;
top: 0;
bottom: 0;
right: -32px;
margin: auto;
color: #888;
font-size: 80%;
}
.infoActive .videoDetailToggleButton:hover::after {
content: '▲';
}
{* プレイリスト出したり隠したり *}
#playlist>* {
-webkit-transition: opacity 0.6s; transition: opacity 0.6s;
}
body:not(.full_with_browser):not(.videoExplorer) #playlist.w_closing>* {
opacity: 0;
}
body:not(.full_with_browser):not(.videoExplorer) #playlist:not(.w_show){
position: absolute; top: -9999px;
}
#playlist.w_show{
{*max-height: 180px;*}
}
.playlistToggle::after {
content: "▼";
}
.playlistToggle.w_show::after {
content: "▲";
}
body.videoExplorer #content.w_adjusted #playlist .playlistInformation {
white-space: nowrap;
}
body.videoExplorer #content.w_adjusted #playlist .playlistInformation  .playbackOption {
position: absolute;
}
body.videoExplorer #content.w_adjusted #playlist .playlistInformation  .generationMessage{
margin-left: 90px; max-width: 350px; overflow: hidden; text-overflow: ellipsis;
}
body.videoExplorer #content.w_adjusted #playlist .playlistInformation .browserFullOption {
position: absolute; right: 0; top: 0;
}
body.videoExplorer #content.w_adjusted #playlist .playlistInformation .browserFullOption a {
background: #444;
}
#playlistContainerInner .thumbContainer, #playlistContainerInner .balloon{
cursor: move;
}
{* ページャーの字が小さくてクリックしにくいよね *}
#r###ltPagination {
padding: 5px; font-weight: bolder; border: 1px dotted silter; font-size: 130%;
}
#playlistContainer #playlistContainerInner .playlistItem .balloon {
bottom: auto; top: -2px; padding: auto;
}
body.w_channel #leftPanel .userIconContainer{
display: none;
}
{* WatchItLater設定パネル *}
#watchItLaterConfigPanel {
position: fixed; bottom: 0px; right: 16px; z-index: 10001;
width: 460px; padding: 0;
transition: transform 0.4s ease-in-out; -webkit-transition: -webkit-transform 0.4s ease-in-out;
transform-origin: 50% 0; -webkit-transform-origin: 50% 0;
transform: scaleY(0);  -webkit-transform: scaleY(0);
}
#watchItLaterConfigPanel.open {
transform: scaleY(1); -webkit-transform: scaleY(1);
}
#watchItLaterConfigPanelShadow {
position: fixed; bottom: 16px; right: 16px; z-index: 10000;
width: 460px; height: 559px; padding: 0;
background: #000; {*box-shadow: 0 0 2px black; border-radius: 8px;*} -webkit-filter: opacity(70%);
transition: transform 0.4s ease-in-out; -webkit-transition: -webkit-transform 0.4s ease-in-out;
transform-origin: 50% 0; -webkit-transform-origin: 50% 0;
transform: scaleY(0); -webkit-transform: scaleY(0);
}
#watchItLaterConfigPanelShadow.open {
transform: scaleY(1); -webkit-transform: scaleY(1);
}
#watchItLaterConfigPanelShadowTop {
position: fixed; bottom: 563px; right:0px; z-index: 10000; background: #333;
width: 492px; height: 20px; padding: 0; border-radius: 32px; -webkit-filter: opacity(90%); display: none;
}
#watchItLaterConfigPanelOverShadow {
position: fixed; bottom: 575px; right: 0px; width: 488px; height: 8px;
box-shadow: 0 4px 16px #333;z-index: 10002; display: none;
}
#watchItLaterConfigPanel .head {
background-color: #CCCCCC;border-radius: 0;color: black;height: 50px;
overflow: hidden;padding: 5px 0 0 16px;position: relative;
}
#watchItLaterConfigPanel .head h2 {
font-size: 135%;
}
#watchItLaterConfigPanel .inner{
height: 500px; overflow-y: auto;border-width: 4px 16px 16px 16px; border-radius: 0 0 16px 16px;
border-style: solid;border-color: #ccc;
}
#watchItLaterConfigPanel ul{
border-style: inset; border-color: #ccc; border-width: 0 1px 0;
}
#watchItLaterConfigPanel ul.shortcutContainer{
border-width: 0 1px 1px;
}
#watchItLaterConfigPanel ul.videoStart{
border-width: 1px 1px 0;
}
#watchItLaterConfigPanel li{
}
#watchItLaterConfigPanel li:hover{
{*background: #ddd;*}
}
#watchItLaterConfigPanel li.buggy{
color: #888;
}
#watchItLaterConfigPanel label{
margin: 0 5px;
}
#watchItLaterConfigPanel label:hover{
}
#watchItLaterConfigPanel .foot {
text-align: right; padding: 0 12px;
}
#watchItLaterConfigPanel .closeButton{
border: 0 none;border-radius: 0 0 4px 4px;box-shadow: 0 1px 2px white;color: #666; border: 1px solid #999;
cursor: pointer;float: right;margin-top: 8px;position: absolute;right: 16px;
text-shadow: 0 1px 0 white;top: -10px; width: 60px;
}
#watchItLaterConfigPanel.autoBrowserFull_false .disableAutoBrowserFullIfNicowari,
#watchItLaterConfigPanel.autoBrowserFull_true .autoScrollToPlayer,
#watchItLaterConfigPanel.autoBrowserFull_true .autoOpenSearch,
#watchItLaterConfigPanel.removeLeftPanel_true .leftPanelJack  {
color: #ccc; text-shadow: -1px -1px 0 #888;
}
#watchItLaterConfigPanel .reload .title::after {
content: ' (※)'; font-size: 80%; color: #900;
}
#watchItLaterConfigPanel .debugOnly {
display: none;
}
#watchItLaterConfigPanel.debugMode .debugOnly {
display: block; background: #888;
}
#watchItLaterConfigPanel .section {
border-style: solid;border-width: 10px 12px 10px 12px;color: white; font-size: 135%; position: relative;
font-weight: bolder; cursor: pointer; {*text-shadow: 2px 2px 1px #000000;*}
transition: border-width 0.2s ease-in-out 0.4s, color 0.3s; -webkit-transition: border-width 0.2s ease-in-out 0.4s, color 0.4s;
}
#watchItLaterConfigPanel .open .section {
border-width: 20px 12px 12px 12px;
transition: border-width 0.2s ease-in-out     ; -webkit-transition: border-width 0.2s ease-in-out     ;
}
#watchItLaterConfigPanel .section:hover::after {
content: '▼';
position: absolute; top: 0px; right: 10px; font-size: 150%;
transition: transform 0.2s ease-in-out 0.4s; -webkit-transition: -webkit-transform 0.2s ease-in-out 0.4s;
}
#watchItLaterConfigPanel .open .section::after {
content: '▼';
position: absolute; top: 0px; right: 10px; font-size: 150%;
transform: rotate(180deg); -webkit-transform: rotate(180deg);
transition: transform 0.2s ease-in-out     ; -webkit-transition: -webkit-transform 0.2s ease-in-out;
}
#watchItLaterConfigPanel .section > div {
padding: 8px 0 8px 12px; box-shadow: 0 0 4px black;
}
#watchItLaterConfigPanel .section > div > span {
{*background: #333;*}
}
#watchItLaterConfigPanel li:not(.section) {
background: #fff; border-width: 0px 0px 0px 24px; border-style: solid; border-color: #fff;
max-height: 0px; overflow: hidden;
transition: max-height 0.4s ease-in-out     , border-width 0.4s ease-in-out;
}
#watchItLaterConfigPanel .open li:not(.section) {
max-height: 100px; border-width: 4px 0px 4px 24px;
transition: max-height 0.4s ease-in-out 0.2s, border-width 0.4s ease-in-out 0.2s;
}
#watchItLaterConfigPanel .section .description{
display: block; font-size: 80%;;
}
#watchItLaterConfigPanel .shortcutSetting:not(.enable) span :not(.enable){
color: silver;
}
#watchItLaterConfigPanel .shortcutSetting .enable {
cursor: pointer; margin: auto 10px;
}
#watchItLaterConfigPanel .shortcutSetting        .enable::before {
content: '○ ';
}
#watchItLaterConfigPanel .shortcutSetting.enable .enable::before {
content: '㋹ '; color: blue;
}
#watchItLaterConfigPanel .shortcutSetting      .ctrl, #watchItLaterConfigPanel .shortcutSetting     .alt, #watchItLaterConfigPanel .shortcutSetting       .shift {
cursor: pointer; border: 2px outset; margin: 4px 4px; padding: 2px 4px; width: 180px; border-radius: 4px;background: #eee;
}
#watchItLaterConfigPanel .shortcutSetting.ctrl .ctrl, #watchItLaterConfigPanel .shortcutSetting.alt .alt, #watchItLaterConfigPanel .shortcutSetting.shift .shift {
border: 2px inset; color: blue;
}
#watchItLaterConfigPanel .hoverMenuDelay input {
width: 50px; ime-mode: disabled; text-align: center;
}
{* 動画検索画面に出るお気に入りタグ・お気に入りマイリスト *}
.videoExplorerMenu .watchItLaterMenu.open,
.videoExplorerMenu .watchItLaterMenu.opening {
background: -moz-linear-gradient(center top , #D1D1D1, #FDFDFD) repeat scroll 0 0 transparent !important;
background: -webkit-gradient(linear, left top, left bottom, from(#D1D1D1), to(#FDFDFD)) !important;
border-bottom: 0 !important;
}
.videoExplorerMenu .watchItLaterMenu {
position: relative;
{*background: -moz-linear-gradient(center top , whitesmoke 0%, #E1E1E1 100%) repeat scroll 0 0 transparent;*}
{*box-shadow: 0 -1px 1px rgba(0, 0, 0, 0.1) inset;*}
{*background: #f5f5f5;*}
border-bottom: 1px solid #CCCCCC;
}
.videoExplorerMenu .watchItLaterMenu:hover{
background: #dbdbdb;
}
.videoExplorerMenu .watchItLaterMenu {
padding: 0 12px; display: block; color: black;
}
.videoExplorerMenu .slideMenu{
width: 100%; height: auto !important;
overflow-x: hidden;
overflow-y: auto;
padding: 0;
background: #fdfdfd;
border-top: 0 !important;
display: block;
max-height: 0;
transition: max-height 0.5s ease-in-out;
}
.videoExplorerMenu .slideMenu.open {
max-height: 2000px;
transition: max-height   1s ease-in-out;
}
.videoExplorerMenu .toggleVideoExplorerMenu a {
color: black; display: block;
}
.videoExplorerMenu .toggleVideoExplorerMenu a::after {
content: "▼"; position: absolute; background: none; top: 0px; right: 10px; color: #ccc;
}
.videoExplorerMenu .toggleVideoExplorerMenu.open a::after {
content: "▲";
}
.videoRankingList .isCategory {
position: relative;
}
.rankingCategoryToggle {
position: absolute;
display: none;
height: 20px;
padding: 0px 8px;
right: 14px;
top: 0;
cursor: pointer;
border: 1px solid;
color: #666;
outline: none;
}
.rankingCategoryToggle::-moz-focus-inner {
border: 0px;
}
.slideMenu.open  .isCategory:hover .rankingCategoryToggle {
display: block;
}
.categoryClose .rankingCategoryToggle .close, .rankingCategoryToggle .open{
display: none;
}
.categoryClose .rankingCategoryToggle .open{
display: inline;
}
.videoRankingList li:not(.isCategory) {
transition: max-height 0.5s;
max-height: 50px; overflow:hidden;
margin-left: 8px;
}
.videoRankingList .categoryClose:not(.isCategory) {
max-height: 0px;
}
.videoExplorerMenu .slideMenu ul{
}
.videoExplorerMenu .slideMenu ul li{
background: #fdfdfd; padding: 0; border: 0;font-size: 90%; height: auto !important;
}
.videoExplorerMenu .slideMenu ul li a{
line-height: 165%; background: none; display: block;
}
.videoExplorerMenu.w_touch .slideMenu ul li a{
line-height: 300%; font-size: 120%; color: black;
}
.videoExplorerMenu .slideMenu ul li a::before{
background: url("http://uni.res.nimg.jp/img/zero_my/icon_folder_default.png") no-repeat scroll 0 0 transparent;
display: inline-block;
height: 14px;
margin: -4px 4px 0 0;
vertical-align: middle;
width: 18px;
content: ""
}
.videoExplorerMenu .slideMenu ul li          a.defMylist::before{ background-position: 0 -253px;}
.videoExplorerMenu .slideMenu ul li.folder0  a::before{ background-position: 0 0;}
.videoExplorerMenu .slideMenu ul li.folder1  a::before{ background-position: 0 -23px;}
.videoExplorerMenu .slideMenu ul li.folder2  a::before{ background-position: 0 -46px;}
.videoExplorerMenu .slideMenu ul li.folder3  a::before{ background-position: 0 -69px;}
.videoExplorerMenu .slideMenu ul li.folder4  a::before{ background-position: 0 -92px;}
.videoExplorerMenu .slideMenu ul li.folder5  a::before{ background-position: 0 -115px;}
.videoExplorerMenu .slideMenu ul li.folder6  a::before{ background-position: 0 -138px;}
.videoExplorerMenu .slideMenu ul li.folder7  a::before{ background-position: 0 -161px;}
.videoExplorerMenu .slideMenu ul li.folder8  a::before{ background-position: 0 -184px;}
.videoExplorerMenu .slideMenu ul li.folder9  a::before{ background-position: 0 -207px;}
.videoExplorerMenu .slideMenu ul li.g_ent2 a::before     {  background-position: 0 -23px;}
.videoExplorerMenu .slideMenu ul li.g_life2 a::before    {  background-position: 0 -46px;}
.videoExplorerMenu .slideMenu ul li.g_politics a::before {  background-position: 0 -69px;}
.videoExplorerMenu .slideMenu ul li.g_tech a::before     {  background-position: 0 -92px;}
.videoExplorerMenu .slideMenu ul li.g_culture2 a::before {  background-position: 0 -115px;}
.videoExplorerMenu .slideMenu ul li.g_other a::before    {  background-position: 0 -138px;}
.videoExplorerMenu .slideMenu ul li.r18 a::before        {  background-position: 0 -207px;}
.videoExplorerMenu .slideMenu ul li.all        a.all,
.videoExplorerMenu .slideMenu ul li.g_ent2     a.g_ent2,
.videoExplorerMenu .slideMenu ul li.g_life2    a.g_life2,
.videoExplorerMenu .slideMenu ul li.g_politics a.g_politics,
.videoExplorerMenu .slideMenu ul li.g_tech     a.g_tech,
.videoExplorerMenu .slideMenu ul li.g_culture2 a.g_culture2,
.videoExplorerMenu .slideMenu ul li.g_other    a.g_other,
.videoExplorerMenu .slideMenu ul li.r18        a.r18
{ font-weight: bolder; border-top: 1px dotted #ccc; }
.videoExplorerMenu .slideMenu ul li a::after{
background: none !important;
}
.videoExplorerMenu .slideMenu ul li a:hover{
background: #f0f0ff;
}
.videoExplorerMenu .slideMenu ul .reload{
cursor: pointer; border: 1px solid; padding: 0;
}
.videoExplorerMenu .tagSearchHistory {
border-radius: 0px; margin-top: 2px; padding: 4px; background: #ccc;
}
.videoExplorerMenu .itemList > li, #videoExplorerExpand {
background: #f5f5f5;
}
.videoExplorerMenu .itemList ul > li:hover {
background: #e7e7e7;
}
.videoExplorerMenu .itemList ul > li.active {
background: #343434;
}
{* 動画タグが1行以下の時 *}
body:not(.full_with_browser) .tag1Line  #videoTagContainer .tagInner #videoHeaderTagList .toggleTagEdit {
height: 12px; padding: 6px 4px 2px;
}
body:not(.full_with_browser) .tag1Line  #videoTagContainer .tagInner #videoHeaderTagList .toggleTagEdit .toggleText{
display: none;
}
{* 動画タグが2行以下の時 *}
body:not(.full_with_browser) .tag2Lines #videoTagContainer .tagInner #videoHeaderTagList .toggleTagEdit {
height: 36px;
}
{* タグ#域とプレイヤーの隙間をなくす *}
body:not(.full_with_browser) #videoTagContainer, body:not(.full_with_browser) #videoHeader .videoMenuToggle {
margin-bottom: -10px;
}
#videoHeaderMenu .searchContainer .searchText {
margin-top: -8px;
}
#videoHeaderMenu .clear-button {
position: absolute;
top: -8px;
right: 0px;
}
body.size_small #playerContainerWrapper {
padding: 0;
}
{* ニュース履歴 *}
body.videoExplorer #textMarquee .openNewsHistory, body.videoExplorer #textMarquee .newsHistory {
display: none;
}
#textMarquee .openNewsHistory {
position: absolute; width: 30px;
font-size: 13px; padding: 0; margin: 0; height: 28px;
cursor: pointer;
bottom: 0;
background: none repeat scroll 0 0 transparent;
border: 1px none;
border-radius: 2px 2px 2px 2px;
cursor: pointer;
right: 18px;
z-index: 200;
}
#textMarquee .newsHistory {
position: absolute;
bottom: 0px; right: 0px; width: 100%;
max-height: 132px;
min-height: 40px;
overflow-y: auto;
overflow-x: hidden;
z-index: 1;
padding: 4px;
display: none;
background: #333;
text-align: left;
font-size: 14px;
padding: 0;
}
#textMarquee .newsHistory li{
padding: 0 2px;
}
#textMarquee .newsHistory li:nth-child(odd){
background: #444;
}
#textMarquee .newsHistory li:nth-child(even){
background: #333;
}
body #popupMarquee {
width: 360px;
}
{* 半透明だとflashの上に来ると描画されないので強制的に黒にする(Chromeは平気) *}
body.full_with_browser #popupMarquee.popupMarqueeBottomLeft {
background: #000 !important; width: 400px; opacity: 1;
}
body.full_with_browser #playerContainer {
margin-left: 0 !important;
}
body:not(.full_with_browser) #playerContainerWrapper {
padding: 0px;
}
body.full_with_browser #playerContainer, body.size_small #playerContainer {
top: auto;
}
body.full_with_browser.no_setting_panel .videoExplorerMenu {
display:none;
}
body:not(.videoExplorer) {*#playlist:not(.nico-bucket-videoExplorer-b)*} #videoExplorerExpand {
display: none;
}
#outline .openVideoExplorer {
display: none;
}
#outline.w_hideSearchExpand .openVideoExplorer {
display: inline-block;
}
.videoExplorerMenu .quickSearchInput {
background: none repeat scroll 0 0 #F4F4F4;
border: 1px inset silver;
left: 60px;
padding-left: 4px;
position: absolute;
top: 2px;
width: 180px;
}
.videoExplorerMenu.w_touch .quickSearchInput {
top: 4px; font-size: 20px;
}
.videoExplorerMenu .clear-button {
position: absolute;
width: 20px;
height: 20px;
top: 4px;
left: 250px;
line-height: 18px;
font-size: 16px;
padding: 0;
background: #e5e5e5;
text-align: center;
color: #999;
cursor: pointer;
display: none;
box-sizing: border-box;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
}
.videoExplorerContent .contentItemList                 .column4 {
text-align: center;
}
.videoExplorerContent .contentItemList                 .column4 .balloon {
bottom: auto; top: 10px;
}
.videoExplorerContent .contentItemList                 .column4 .videoInformation>.info {
font-size: 85%;
}
.videoExplorerContent .contentItemList                 .column4 .videoInformation>.info .info{
color: #000;
}
.videoExplorerContent .contentItemList                 .column4 .videoInformationOuter {
width: 100px; height: 48px; margin: auto; color: #666; text-align: left;
}
.videoExplorerBody .videoExplorerContent .contentItemList.column4 .item {
height: 220px;
}
.column1 .mylistCommentEdit {
}
.column1 .mylistCommentEdit.updating {
opacity: 0.5;
}
.column1 .mylistCommentEdit.updating * {
cursor: pointer;
}
.column1 .mylistCommentEdit .startEditButton {
display: none;
}
.isMine .column1 .mylistCommentEdit .startEditButton {
display: inline-block;
width: 16px;
height: 16px;
margin: 4px 8px;
float: right;
vertical-align: middle;
background: url(http://uni.res.nimg.jp/img/zero_my/icon_write.png) no-repeat;
cursor: pointer;
}
.isMine .column1 .mylistCommentEdit.edit .startEditButton {
display: none;
}
.column1 .mylistCommentEdit      .mylistCommentInput {
display: none;
}
.isMine .column1 .mylistCommentEdit.edit .mylistCommentInput {
display: block;
width: 100%;
box-sizing: border-box;
border: inset 1px #ccc;
margin: 4px auto;
border-radius: 4px;
}
.isMine .column1 .mylistCommentEdit.edit .mylistComment {
display: none !important;
}
.column1 .mylistComment {
font-size: 85%; color: #666; display: none;
color: #400; border: 1px solid #ccc; padding: 0 4px 0px; line-height: 130%; border-radius: 4px;
}
.isMine .column1 .mylistComment {
display: block !important;
}
.isMine .column1 .mylistComment {
padding-right: 20px;
}
.column1 .mylistComment::before {
content: 'マイリストコメント ';
background: #ccc; border-radius: 0 0 8px 0; display: inline-block; margin: 0 4px 4px -4px; padding: 2px;
min-width: 100px;
}
.log-user-video-review .column1 .mylistComment {
color: #004;
}
.log-user-video-review .column1 .mylistComment::before {
content: 'レビュー ';
}
.column1 .mylistComment::after {
content: '';
}
.column1 .mylistComment pre {
font-family: inherit;
display: inline;
white-space: pre-wrap;
}
.videoExplorerContent .contentItemList                 .column1 .nicorepoOwnerIconContainer {
display: none;
}
.videoExplorerContent .contentItemList .nicorepoR###lt .column1 .nicorepoOwnerIconContainer {
float: right; display: block;
padding: 24px 14px 0 4px;
}
.videoExplorerContent .contentItemList                 .column1 .nicorepoOwnerIconContainer img {
height: 48px;
}
.videoExplorerBody.dummyMylist #searchR###ltContainer .favMylistEditContainer,
.videoExplorerBody.dummyMylist:not(.ranking) #searchR###ltMylistSortOptions,
.videoExplorerBody.dummyMylist .favMylistEditContainer,
.videoExplorerBody.dummyMylist:not(.ownerNicorepo) #searchR###ltHeader {
display: none !important;
}
.videoExplorerContent .contentItemList .thumbnailHoverMenu {
position: absolute; padding: 0; z-index: 100;
display: none;
bottom: -1px; left: 0px;
}
.videoExplorerContent .contentItemList .deleteFromMyMylist {
cursor: pointer; font-size: 70%; border: 1px solid #ccc; padding: 0;
display: none;
}
.videoExplorerContent .contentItemList .showLargeThumbnail {
cursor: pointer; font-size: 70%; border: 1px solid #ccc;;
}
.videoExplorerContent .contentItemList .showLargeThumbnail {
padding: 0 4px;
}
.videoExplorerContent .contentItemList .item:hover .thumbnailHoverMenu {
display: block;
}
.videoExplorerContent .contentItemList .log-user-video-upload {
background: #ffe; border-radius: 4px;
}
.videoExplorerContent .contentItemList .nicorepoR###lt .itemVideoDescription, .videoExplorerContent .contentItemList .nicorepoR###lt .videoTitle{
}
.videoExplorerContent .contentItemList.channelGuideVideo {
background: #eff; {* 検索結果にチャンネル動画が紛れ込むようになったのでわかりやすく *}
}
#videoExplorer.w_deflist .videoExplorerBody.isMine.enableMylistDeleteButton .item:hover .deleteFromMyMylist,
#videoExplorer.w_mylist  .videoExplorerBody.isMine.enableMylistDeleteButton .item:hover .deleteFromMyMylist
{
display: inline-block;
}
#playlist .generationMessage {
cursor: pointer;
}
#playlist .generationMessage:hover {
text-decoration: underline;
}
#playlist .generationMessage::after {
content: "▼";
}
#yukkuriPanel {
position: fixed; z-index: 1500; bottom: 0; left: 0; display: inline-block;
transition: bottom 0.2s ease;
}
#yukkuriPanel.mylistPanelLeft {
bottom: 24px;
}
body #videoTagContainer .tagInner #videoHeaderTagList li {
margin: 0 18px 4px 0;
}
body #videoTagContainer .tagInner #videoHeaderTagList li .tagControlContainer,
body #videoTagContainer .tagInner #videoHeaderTagList li .tagControlEditContainer {
padding: 1px 0;
}
.userProfile.w_touch {
font-size: 150%; line-height: 120%;
}
.r###ltPagination.w_touch {
font-size: 200%;
}
.r###ltPagination.w_touch li{
padding: 4px 16px;
}
select.w_touch {
font-size: 200%;
}
{* 真・browserFullモード *}
body.full_with_browser.hideCommentInput #nicoplayerContainerInner {
{* コメント入力欄は動画上表示にするのではなく、画面外に押し出す事によって見えなくする *}
margin-top: -10px; margin-bottom: -30px !important;
}
body.full_with_browser.w_hideControlPanel #nicoplayerContainerInner,
body.full_with_browser.hideCommentInput.w_hideControlPanel #nicoplayerContainerInner {
margin-bottom: -76px !important;
}
{*body.full_with_browser:not(.w_fullScreenMenu) .mylistPopupPanel.fixed,*}
body.full_with_browser                        .yukkuriButton
{ display:none; }
#fullScreenMenuContainer {
-webkit-transition: opacity 0.2s ease-out;
position:absolute;
display: none;
}
body.full_with_browser #fullScreenToggleContainer {
background: black;
display: block;
bottom: 100px;
right:  50px;
z-index: 10000;
min-width: 400px;
cursor: nw-resize;
opacity: 0;
color: white;
box-shadow: 2px 2px 2px silver;
border-radius: 4px;
}
body.full_with_browser #fullScreenToggleContainer .title {
color: #ffc; font-size: 120%;
}
body.full_with_browser #fullScreenToggleContainer .ownerIcon {
float: left; height: 55px; padding: 8px;
}
body.full_with_browser #fullScreenToggleContainer:hover, body.full_with_browser #fullScreenToggleContainer.active, body.w_fullScreenMenu #fullScreenToggleContainer {
opacity: 1;
}
body:not(.full_with_browser) #fullScreenToggleContainer { display: none; }
#sharedNgSettingContainer {
display: inline-block; font-size: 80%; position: absolute; top: -18px; left: 5px;
}
#sharedNgSetting {
background: #ddd; border: 1px solid silver;
}
{* ニュース消す *}
#content.noNews #textMarquee {
display: none !important;
}
body:not(.videoExplorer):not(.full_with_browser) #content.noNews #playerContainer {
min-height: 461px;
}
body:not(.videoExplorer):not(.setting_panel):not(.full_with_browser) #content.noNews #playerTabWrapper {
height: auto !important; position: absolute; bottom: 18px;
}
body:not(.videoExplorer):not(.setting_panel):not(.full_with_browser) #content.noNews #playerTabContainer {
bottom: -17px;
}
body:not(.videoExplorer):not(.setting_panel):not(.full_with_browser) #content.noNews #playerContainer.appli_panel #playerTabContainer {
bottom:  20px;
}
#playerTabWrapper.w_videoInfo #playerTabContainer, #playerTabWrapper.w_ichiba #playerTabContainer, #playerTabWrapper.w_review #playerTabContainer {
bottom: 0px !important;
}
body:not(.videoExplorer):not(.setting_panel):not(.full_with_browser) #content.noNews #playerTabWrapper.w_videoInfo,
body:not(.videoExplorer):not(.setting_panel):not(.full_with_browser) #content.noNews #playerTabWrapper.w_ichiba,
body:not(.videoExplorer):not(.setting_panel):not(.full_with_browser) #content.noNews #playerTabWrapper.w_review
{
height: auto !important; position: absolute; bottom: 2px;
}
{* body:not(.videoExplorer):not(.setting_panel):not(.full_with_browser) #content.noNews #leftPanel {
height: auto !important; position: absolute; bottom: 2px;
}*}
body:not(.videoExplorer):not(.setting_panel):not(.full_with_browser) #content.noNews #playerCommentPanel {
height: 100% !important;
}
body:not(.videoExplorer):not(.setting_panel):not(.full_with_browser) #content.noNews #playerContainer.appli_panel #appliPanel {
bottom: -18px !important;
}
body:not(.videoExplorer):not(.setting_panel):not(.full_with_browser) #content.noNews #playerContainer {
height: auto;
}
#outline.noIchiba  #nicoIchiba, #outline.noReview  #videoReview{
display: none;
}
#bottomContentTabContainer.noBottom .outer, #bottomContentTabContainer.noBottom #pageFooter, .noBottom #superBanner{
display: none !important;
}
#bottomContentTabContainer.noBottom #outline {
background: #141414; padding-top: 0; padding-bottom: 35px;
}
#content.w_flat_gray  #playerContainerWrapper {
background: #666;
}
#content.w_flat_white #playerContainerWrapper {
background: #f4f4f4;
}
#content.w_flat_gray #wallImageContainer, #content.w_flat_white #wallImageContainer,
#content.w_flat_gray #chipWallList,       #content.w_flat_white #chipWallList {
display: none !important;
}
#content #chipWallList {
right: auto; left: -42px;
}
#content #playlist .playlistInformation {
background: #444;
}
#content #videoExplorerExpand a {
text-shadow: none;
}
.videoMenuToggle {
-webkit-transform-origin: 100% 100%; -webkit-transition: -webkit-transform 0.4s;
transform-origin: 100% 100%; transition: transform 0.4s;
z-index: 1000;
}
#content.w_compact .videoHeaderTitle {
display: inline-block;
width: 100%;
overflow: hidden;
letter-spacing: -1px;
text-overflow: ellipsis;
white-space: nowrap;
}
#content.w_compact .videoDetailExpand .arrow {
position: absolute; top: 8px; right: -24px;
}
#content.w_compact .tag1Line  .videoMenuToggle {
transform: scale(0.8, 0.41); -webkit-transform: scale(0.8, 0.41);
}
#content.w_compact .tag2Lines .videoMenuToggle {
transform: scale(0.8); -webkit-transform: scale(0.8);
}
#content.w_compact #topVideoInfo .parentVideoInfo {
margin-top: -9px; margin-bottom: 9x;
}
#content.w_compact #topVideoInfo .parentVideoInfo .cct{
margin-bottom: 0;
}
#content.w_compact #topVideoInfo .parentVideoInfo .videoThumb{
margin-top: 4px;
}
#content.w_compact #topVideoInfo .ch_prof, #content.w_compact #topVideoInfo .userProfile {
min-width: 297px; margin-top: -1px; border: 1px solid #e7e7e7;
}
#content.w_compact #videoHeaderDetail .videoDetailExpand{
height: auto; padding: 0;
}
#content.w_compact        #topVideoInfo .videoDescription.description {
background: #fff; margin: 10px 0 0;padding: 4px ;width: 1000px;{* base - 8 *} {*font-size: 90%;*}
}
.size_normal #videoHeaderDetail {
margin: 2px 0;
}
.size_normal #videoHeaderDetail h2 {
max-width: 898px;
}
{* 本家の幅が変わったら変える必要がある。 変数化した方が楽かも base = 1008 *}
body:not(.full_with_browser):not(.videoExplorer).size_normal #content.w_compact.w_wide #topVideoInfo .videoDescription.description {
width: 1318px; {* base + 310 *}
}
body:not(.full_with_browser):not(.videoExplorer).size_normal #content.w_compact        #topVideoInfo .videoDescription.description {
width: 1226px; {* base + 218 *}
}
body:not(.full_with_browser)                                 #content.w_compact.w_wide #topVideoInfo .videoDescription.description {
width: 1092px; {* base +  84 *}
}
body:not(.full_with_browser).size_normal                     #content.w_compact.w_wide #videoTagContainer {
width: 1263px; {* base + 255 *}
margin-top: 0;
}
body:not(.full_with_browser)                                 #content.w_compact.w_wide #videoTagContainer {
width: 1040px; {* base +  32 *}
margin-top: 0;
}
body:not(.full_with_browser)                                 #content.w_compact        #videoTagContainer {
width: 948px;  {* base -  60 *}
margin-top: 0;
}
body:not(.full_with_browser)                                 #content.w_compact #videoHeader,              #foot_inner {
width: 1008px; {* base +  48 *}
}
body:not(.full_with_browser).size_normal                     #content.w_compact #videoHeader, .size_normal #foot_inner {
width: 1234px;  {* base + 226 *}
}
body:not(.full_with_browser)                                 #content.w_compact.w_wide #videoHeader {
width: 1100px;
}
body:not(.full_with_browser).size_normal                     #content.w_compact.w_wide #videoHeader {
width: 1326px;
}
#content.w_compact #topVideoInfo .videoMainInfoContainer{
padding: 0;
}
#content.w_compact #videoDetailInformation{
border-top: 0;
}
#content.w_compact #videoHeaderMenu .searchContainer {
top: -16px;
}
#content.w_compact .videoInformation{
margin: -4px 0 ;
}
#content.w_compact #topVideoInfo .videoStats {
margin-bottom: 2px;
}
body:not(.full_with_browser) #content.w_compact #videoTagContainer .tagInner #videoHeaderTagList .toggleTagEdit {
width: 72px;
}
body:not(.full_with_browser) #content.w_compact #videoTagContainer .tagInner #videoHeaderTagList {
padding-left: 85px;
}
body.full_with_browser #videoHeaderTagList { background: #fafafa; }
#content.w_compact #topVideoInfo {
margin: 4px 0 4px;
}
#content.w_compact #topVideoInfo .videoShareLinks .socialLinks {
margin-top: -6px;
}
#outline.w_compact  #videoInfoHead{
margin: 0 ;
}
#outline.w_compact .videoInformation #videoTitle {
margin: -4px 0 0;
}
#outline.w_compact .videoInformation #videoStats  {
margin-top: -4px;
}
#outline.w_compact .videoInformation #videoStats .ranking {
margin: 0 0 4px;
}
#outline.w_compact #videoShareLinks {
margin: 0;
}
#outline.w_compact #bottomVideoDetailInformation {
margin: -18px 0 0;
}
#outline.w_compact .infoHeadOuter .videoEditMenuExpand {
position: absolute; top: 0;
}
#outline.w_compact .videoEditMenu {
margin: 0;
}
#outline.w_compact .videoDescription {
font-size: 90%; margin-top: -8px; padding: 0 0 4px 4px;
}
#outline.w_compact #videoComment {
margin: 0px; border: 1px solid silver; border-radius: 4px 4px 4px 4px; padding: 0 4px;
}
#outline.w_compact #videoComment h4{
padding-left: 4px;
}
#outline.w_compact .videoMainInfoContainer {
border-bottom: 0; margin-bottom: 0;
}
#outline.w_compact {
border-bottom: 0; margin-bottom: 0;
}
#outline.w_compact .sidebar { width: 300px; }
#outline.w_compact #ichibaMain dl.ichiba_mainitem {
margin: 0 22px 30px 0;
}
#footer     { z-index: 1; }
body.en-us #playerAlignmentArea, body.zh-tw #playerAlignmentArea {
{*padding-right: 0;*}
}
#footer .toggleBottom {
cursor: pointer; text-align: center; width: 200px; padding: 0px 12px; margin: auto; border-radius: 16px 16px 0 0;
border: 1px solid #333; background: #666; transition: background 0.4s ease-out, box-shadow 0.4s;
}
#footer:hover .toggleBottom {
border: 1px outset; background: #ccc;
}
#footer .toggleBottom:hover {
box-shadow: 0px 0px 8px #fff;
}
#footer.noBottom .toggleBottom {
border-radius: 0 0 16px 16px;
}
#footer .toggleBottom .openBottom, #footer.noBottom .toggleBottom .closeBottom  {
display: none;
}
#footer.noBottom .toggleBottom .openBottom {
display: block;
}
#footer .toggleBottom>div {
-webkit-transform: scaleX(3); transform: scaleX(3);
}
#footer .toggleBottom {
cursor: pointer; text-align: center; width: 200px; padding: 0px 12px; margin: auto; border-radius: 16px 16px 0 0;
border: 1px solid #333; background: #666; transition: background 0.4s ease-out, box-shadow 0.4s;
}
#footer:hover .toggleBottom {
border: 1px outset; background: #ccc;
}
#footer .toggleBottom:hover {
box-shadow: 0px 0px 8px #fff;
}
#footer.noBottom #foot_inner { padding: 0; }
#footer.noBottom a:nth-of-type(3)::after, #footer.noBottom a:nth-of-type(6)::after  {
content: ' | '; color: white;
}
#footer.noBottom br { display: none; }
html { background: #141414; }
.videoExplorer #videoExplorer,
.videoExplorer #videoExplorer .videoExplorerBody,
.videoExplorerContentWrapper
{
background: none;
}
.animateBlink {
-webkit-transition: 1s ease-in; transition: 1s ease-in;
}
.w_compact .toggleDetailExpand, .w_compact .shortVideoInfo {
display: none;
}
.videoDetailToggleButton {
cursor: pointer;
}
#leftPanel {
{*border-radius: 4px 4px 4px 4px;*}
display: none; padding: 0; position: absolute; text-align: left; top: 0; z-index: 101;
}
body.ja-jp #leftPanel { display: none; }
body:not(.videoExplorer) #leftPanel { display: none; }
body.full_with_browser #playerTabWrapper, body.full_with_browser:not(.videoExplorer) .w_wide #playerTabWrapper {
top: auto !important; bottom: 3000px !important; right: 50px !important;
transition: bottom 0.2s ease-out; max-height: 500px;
}
body.full_with_browser.w_fullScreenMenu:not(.videoExplorer) #playerTabWrapper {
top: auto !important; bottom:  200px !important; right: 50px !important;
}
#fullScreenMenuContainer { display: none; }
body.full_with_browser #fullScreenMenuContainer {
display: block; position: absolute; bottom: 3000px; left: 50px; z-index: 10000;
background: #fff; cursor: pointer; transition: bottom 0.2s ease-out;
}
body.full_with_browser.w_fullScreenMenu #fullScreenMenuContainer {
bottom: 100px;
}
#fullScreenMenuContainer .button {
cursor: pointer; transition: color 0.4s ease-out;
}
#fullScreenMenuContainer .modeStatus { display: none; font-weight: bolder; }
body:not(.fullWithPlaylist) #fullScreenMenuContainer .fullScreenModeSwitch .playlistClosing,
body.fullWithPlaylist       #fullScreenMenuContainer .fullScreenModeSwitch .playlistOpening
{ display: inline; }
#fullScreenMenuContainer .prevNext {
padding-left: 16px;
padding-right: 16px;
font-weight: bolder;
}
body:fullscreen #fullScreenMenuContainer       .monitorFull {
display: none;
}
body:not(:fullscreen) #fullScreenMenuContainer .monitorFull {
}
body:fullscreen #fullScreenMenuContainer       .closeMonitorFull {
}
body:not(:fullscreen) #fullScreenMenuContainer .closeMonitorFull {
display: none;
}
#nicoplayerContainerInner.stageVideo       #fullScreenMenuContainer .stageVideoSwitch { color: blue; }
#nicoplayerContainerInner:not(.stageVideo) #fullScreenMenuContainer .stageVideoSwitch .mode_off,
#nicoplayerContainerInner.stageVideo       #fullScreenMenuContainer .stageVideoSwitch .mode_on { display: inline; }
body.full_with_browser.w_fullScreenMenu .videoHeaderOuter {
position: absolute; z-index: 1000; width: 100%;
}
body.full_with_browser.w_fullScreenMenu #videoTagContainer {
display: block;
width: 100%;
margin-top: 0;
}
body.full_with_browser.w_fullScreenMenu #videoTagContainer #videoHeaderTagList {
padding-left: 0;
}
body.full_with_browser #videoTagContainer .toggleTagEdit {
display: none !important;
}
.popupMarqueeContent {
background: black;
}
#videoExplorer, #playlist {
transition: margin-left 0.2s ease-in-out;
}
.dummyMylist .editFavorite {
display: none;
}
{* 不要な時まで横スクロールバーが出てしまうので *}
#songrium_inline { overflow: hidden; }
.sideVideoInfo .videoLinkContainer {
display: inline-block;
white-space: nowrap;
}
.sideVideoInfo .nextPlayButton {
position: absolute;
margin-top: -6px;
margin-left: -30px;
width: 30px;
height: 30px;
background: url(http://res.nimg.jp/img/watch_q9/icon_nextplay.png);
{*background: url("http://res.nimg.jp/img/watch_zero/videoexplorer-s90d011f9a7.png") no-repeat scroll -37px 0 rgba(0, 0, 0, 0);*}
z-index: 100;
cursor: pointer;
text-indent: -999em;
overflow: hidden;
display: inline-block;
-webkit-transform: scale(1.0); transform: scale(1.0);
}
.nextPlayButton {
-webkit-transform: scale(1.5); transform: scale(1.5);
transition: transform 0.1s ease; -webkit-transition: -webkit-transform 0.1s ease;
}
.sideVideoInfo .nextPlayButton:hover {
-webkit-transform: scale(1.5); transform: scale(1.5);
}
.nextPlayButton:active, .sideVideoInfo .nextPlayButton:active {
-webkit-transform: scale(1.2); transform: scale(1.2);
}
.sideVideoInfo .nextPlayButton:active {
background-position-y: 30px;
}
body.w_disableHorizontalScroll {
overflow-x: hidden !important;
}
#videoTagContainerPin { display: none !important; } {* タグを固定しているか4行以上の時に現われるピン *}
.w_adjusted #selectionSideAdAds >* {
width: 100%; height: auto; max-width: 300px; max-height: 250px;
}
{* *}
.w_noHover {
pointer-events: none !important;
}
.w_noHover #playlist {
pointer-events: auto !important;
}
{* ソーシャルボタン *}
.area-JP .panel_ads_shown #playerTabContainer.w_noSocial.has_panel_ads .playerTabContent {
bottom: 80px;
}
.area-JP                  #playerTabContainer.w_noSocial               .playerTabContent {
bottom: 4px;
}
.area-JP .panel_ads_shown #playerTabContainer.w_noSocial.has_panel_ads .player-panel-tabs .player-tab-content {
bottom: 80px;
}
.area-JP                  #playerTabContainer.w_noSocial               .player-panel-tabs .player-tab-content {
bottom: 4px;
}
#playerTabContainer.w_noSocial .playerTabAds {
bottom: 0;
}
#playerTabContainer.w_noSocial .socialButtons{
display: none;
}
.w_noSocial .nicoSpotAds {
bottom: 8px;
}
{* テレビちゃんメニュー スライドをやめる *}
body #videoHeader #videoMenuWrapper{
position: absolute; width: 324px; height: auto !important;
opacity: 0;
transition: opacity 0.4s ease;
right: 0px;
}
body #videoHeader.menuOpened #videoMenuWrapper{
z-index: 1000 !important;
border: 1px solid #000;
background: white;
box-shadow: 0px 0px 4px #000;
top: 110px;
bottom: auto;
opacity: 1;
}
body .tag1Line  #videoHeader.menuOpened #videoMenuWrapper{
top: 62px;
}
body .tag2Lines #videoHeader.menuOpened #videoMenuWrapper{
top: 86px;
}
body #videoHeader.infoActive.menuOpened #videoMenuWrapper{
top: auto;
bottom: 48px;
}
{* 開閉時に変なスクロールしてしまう奴 *}
#videoHeader .tvChanMenuHeightController {
display: none !important;
}
body #videoHeader #videoMenuTopList{
position: relative;
width: auto;
}
body #videoHeader.menuOpened #videoMenuWrapper .videoMenuList{
display: inline-block;
width: 60px;
min-height: 72px;
}
body #videoHeader.isAdult .videoMenuToggle, body #videoHeader.noAudioDownload .downloadButton {
display: inline-block;
opacity: 0.5;
pointer-events: none !important;
}
.largeThumbnailPopup, .largeThumbnailPopup div{
background-color: #000;
background-size: contain;
background-repeat: no-repeat;
background-position: center center;
background-size: contain;
-moz-background-size: contain;
-webkit-background-size: contain;
-o-background-size: contain;
-ms-background-size: contain;
}
#nicoSpotAdAds >*:nth-child(2) {
display: none !imortant;
position: fixed;
top: -999px;
}
*/}).toString().match(/[^]*\/\*([^]*)\*\/\}$/)[1]
.replace(/\{\*/g, '/*').replace(/\*\}/g, '*/');
addStyle(__css__, 'watchItLaterStyle');
})(); // end of watchItLaterStyle
conf.load = function() {
try {
function loadStorage(key, def) {
if (window.localStorage[key] === void 0) { return def; }
return JSON.parse(window.localStorage.getItem(key));
}
for (var v in conf) {
if (typeof conf[v] === 'function') { continue; }
conf[v] = loadStorage('watchItLater_' + v, conf[v]);
}
} catch (e) {
}
};
conf.getValue = function(varName) {
return conf[varName];
};
conf.setValue = function(k, v) {
var lastValue = conf[k];
if (lastValue !== v) {
conf[k] = v;
window.localStorage.setItem('watchItLater_' + k, JSON.stringify(v));
EventDispatcher.dispatch('on.config.' + k, v, lastValue);
}
};
conf.load();
var console = (function(conf) {
if (conf.debugMode) { return window.console; }
var noop = function() {};
return {
log: noop,
error: noop,
trace: noop,
warn: noop,
table: noop,
time: noop,
timeEnd: noop
};
})(conf);
var ConfigPanel = (function($, conf, w) { // SettingPanel
var pt = function(){};
var $panel = null, $shadow = null;
var menus = [
{title: '再生開始・終了時の設定', className: 'videoStart'},
{title: '自動で全画面モードにする', varName: 'autoBrowserFull',
values: {'する': true, 'しない': false}, addClass: true},
{title: '自動全画面化オンでも、ユーザーニコ割のある動画は', varName: 'disableAutoBrowserFullIfNicowari',
values: {'全画面化しない': true, '全画面化する': false}},
{title: '自動で検索モードにする(自動全画面化オフ時)', varName: 'autoOpenSearch',
values: {'する': true, 'しない': false}},
{title: '動画の位置に自動スクロール(自動全画面化オフ時)', varName: 'autoScrollToPlayer',
values: {'する': true, 'しない': false}},
//    {title: '終了時に全画面モードを解除(原宿と同じにする)', varName: 'autoNotFull',
//      values: {'する': true, 'しない': false},
//      description: '連続再生中は解除しません'},
{title: 'ウィンドウがアクティブの時だけ自動再生する', varName: 'autoPlayIfWindowActive',
description: 'QWatch側の設定パネルの自動再生はオフにしてください。\n■こんな人におすすめ\n・自動再生ONにしたいけど別タブで開く時は自動再生したくない\n・複数タブ開いたままブラウザ再起動したら全部のタブで再生が始まって「うるせー!」という経験のある人',
values: {'する': 'yes', 'しない': 'no'}},
{title: '動画が切り替わる時、ポップアップでタイトルと再生数を表示', varName: 'popupViewCounter',
description: '全画面状態で連続再生している時などに便利です',
values: {'する': 'always', '全画面時のみ': 'full', 'しない': 'none'}},
{title: 'プレイヤーの設定', className: 'playerSetting'},
{title: 'コメントパネルを広くする', varName: 'wideCommentPanel',
values: {'する': true, 'しない': false}},
{title: 'コメントパネルにNG共有設定を表示', varName: 'enableSharedNgSetting',
values: {'する': true, 'しない': false}, addClass: true},
{title: 'コメントの表示', varName: 'commentVisibility',
values: {'オフ': 'hidden', '最後の状態を記憶': 'lastState', 'オン': 'visible'}},
{title: '右のパネルに動画情報・市場・レビューを表示', varName: 'rightPanelJack', reload: true,
values: {'する': true, 'しない': false}},
{title: 'ページのヘッダに再生数表示', varName: 'headerViewCounter', reload: true,
values: {'する': true, 'しない': false}},
//      {title: 'ニコニコニュースの履歴を保持する', varName: 'enableNewsHistory', reload: true,
//        values: {'する': true, 'しない': false}},
{title: 'ニコニコニュースを消す', varName: 'hideNicoNews',
values: {'消す': true, '消さない': false}},
{title: 'プレイヤーの背景', varName: 'playerBgStyle',
description: 'ウォール機能より優先されます',
values: {'白': 'white', 'グレー': 'gray', 'ウォール': ''}},
{title: 'コメントの盛り上がりをグラフ表示', varName: 'enableHeatMap', reload: true,
description: '動画のどのあたりが盛り上がっているのか、わかりやすくなります',
values: {'する': true, 'しない': false}},
{title: '大画面をもっと大画面にする', varName: 'customPlayerSize',
description: '※有効にするとニコニコニュースが表示できなくなります。',
values: {'フルHD': '1080p', '720p': '720p',  '自動調整(推奨)': 'auto', 'しない': ''}},
{title: 'プレイリスト消えないモード', varName: 'storagePlaylistMode', reload: true,
description: '有効にすると、リロードしてもプレイリストが消えなくなります。',
values:
(conf.debugMode ?
{'ウィンドウを閉じるまで': 'sessionStorage', 'ずっと保持': 'localStorage', 'しない': ''} :
{'有効(ウィンドウを閉じるまで)': 'sessionStorage', '無効': ''})
},
{title: '説明文中の動画IDにサムネイル表示',  varName: 'enableDescriptionThumbnail', reload: true,
//        description: 'Chrome+Tampermonkeyでは動きません',
values: {'有効': true, '無効': false}},
{title: '検索モードの設定', className: 'videoExplorer'},
{title: '検索モードを無効化', varName: 'disableVideoExplorer',
description: '無効にするとタグ検索などが原宿と同じになります。\nただし、自分で検索モードにしている時は検索モードで開きます',
values: {'する': true, 'しない': false}},
{title: 'プレイヤーをできるだけ大きくする (コメントやシークも可能にする)', varName: 'videoExplorerHack',
description: '便利ですがちょっと重いです。\n大きめのモニターだと快適ですが、小さいといまいちかも',
values: {'する': true, 'しない': false}},
{title: 'お気に入りタグを表示', varName: 'enableFavTags',
values: {'する': true, 'しない': false}},
{title: 'お気に入りマイリストを表示', varName: 'enableFavMylists',
description: '更新のあったリストが上に来るので、新着動画のチェックに便利です。',
values: {'する': true, 'しない': false}},
{title: '「マイリストから外す」ボタンを表示', varName: 'enableMylistDeleteButton',
description: 'マイリストの整理に便利。\n ※ 消す時に確認ダイアログは出ないので注意',
values: {'する': true, 'しない': false}},
{title: '検索時に関連タグを表示する', varName: 'enableRelatedTag',
values: {'する': true,  'しない': false}},
//      {title: 'niconico新検索βを使う', varName: 'searchEngine',
//        description: '投稿期間や動画長による絞り込みができるようになります',
//        values: {'使う': 'sugoi',  '使わない': 'normal'}},
{title: '1ページの表示件数', varName: 'searchPageItemCount',
values: {'100件': 100, '50件': 50, '32件': 32}},
{title: '全画面モードの設定', className: 'fullScreen'},
{title: '操作パネルとコメント入力欄を隠す', varName: 'controllerVisibilityInFull',
//        description: '全画面の時は少しでも動画を大きくしたい場合に便利',
values: {'隠す': 'hidden', '隠さない': ''}},
{title: '右下のマイリストメニュー', varName: 'hideMenuInFull',
values: {'完全に消す': 'hideAll', '色だけ変える': '', '目立たなくする': 'hide'}},
{title: 'ホイールを回したら動画情報を出す', varName: 'enableFullScreenMenu',
description: 'ホイールを大きく下に回すとメニューが出ます。タッチパネルも対応',
values: {'する': true, 'しない': false}},
{title: 'ページ下半身の設定', className: 'playerBottom'},
{title: 'ニコニコ市場の表示', varName: 'ichibaVisibility',
values: {'非表示': 'hidden', '表示': 'visible'}},
{title: 'レビューの表示', varName: 'reviewVisibility',
values: {'非表示': 'hidden', '表示': 'visible'}},
{title: '省スペース/軽量化設定', className: 'compact'},
{title: 'タグが2行以内の時に高さを詰める(ピン留め時のみ)', varName: 'enableAutoTagContainerHeight', reload: true,
values: {'詰める': true, '詰めない': false}},
{title: '動画情報の空きスペースを詰める', varName: 'compactVideoInfo',
description: '原宿ぐらいの密度になります。ちょっと窮屈かも',
values: {'詰める': true, '詰めない': false}},
{title: 'タグの自動更新を無効化', varName: 'disableTagReload',
values: {'する': true, 'しない': false}},
{title: '横スクロールバーを出なくする', varName: 'disableHorizontalScroll',
values: {'する': true, 'しない': false}},
{title: 'コメントパネル下のソーシャルボタン', varName: 'hideCommentPanelSocialButtons',
values: {'隠す': true, '隠さない': false}},
{title: 'GPUレイヤーを使用してみる(上級者用)', varName: 'enableGpuLayer', reload: true, debugOnly: true,
description: '環境によっては軽くなる かも しれません',
values: {'する': true, 'しない': false}},
{title: 'その他の設定', className: 'otherSetting'},
{title: '動画リンクにカーソルを重ねたらマイリストメニューを表示', varName: 'enableHoverPopup', reload: true,
description: 'マウスカーソルを重ねた時に出るのが邪魔な人はオフにしてください',
values: {'する': true, 'しない': false}},
{title: '動画リンクにカーソルを重ねてからメニューが出るまでの時間(秒)', varName: 'hoverMenuDelay',
type: 'text', description: '単位は秒。 標準は0.4です'},
{title: 'ニコレポのポップアップを置き換える',       varName: 'replacePopupMarquee', reload: true,
description: '画面隅に出るポップアップの不可解な挙動を調整します',
values: {'する': true, 'しない': false}},
{title: '検索時のデフォルトパラメータ', varName: 'defaultSearchOption', type: 'text',
description: '常に指定したいパラメータ指定するのに便利です\n例: 「-グロ -例のアレ」とすると、その言葉が含まれる動画が除外されます'},
{title: '「@ジャンプ」を無効化', varName: 'ignoreJumpCommand', reload: true,
description: '勝手に他の動画に飛ばされる機能を無効化します。',
values: {'する': true, 'しない': false}},
{title: '「@ジャンプ」によるシーク無効化(無限ループなど)', varName: 'nicoSSeekCount', reload: true,
description: '完全に無効にする以外に、一動画あたりの回数を指定できます',
values: {'2回まで有効': 2, '1回まで有効': 1, '完全無効化': 0, 'しない': -1}},
{title: 'タッチパネル向けモード(画面を右フリックで開始)', varName: 'enableQTouch',
description: '指で操作しやすいように、一部のボタンやメニューが大きくなります',
values: {'使う': true, '使わない': false}},
{title: 'マイリストメニューの位置', varName: 'mylistPanelPosition',
values: {'左下': 'left', '右下': ''}},
{title: '2本目以降の動画だけ自動再生 (※プレミアム用)', varName: 'autoPlay2ndVideo', reload: true,
values: {'する': true, 'しない': false}},
{title: 'マイリストのローカルキャッシュ', varName: 'enableLocalMylistCache', reload: true,
description: '動画がどのマイリストに登録されてるかの情報をキャッシュします。\n「my」ボタンの右クリックを活用する人はおすすめ。',
values: {'有効': true, '無効': false}},
{title: 'マウスとキーボードの設定', description: '※Chromeはコメント入力中も反応してしまいます', className: 'shortcut'},
{title: '背景ダブルクリックで動画の位置にスクロール', varName: 'doubleClickScroll',
description: 'なにもない場所をダブルクリックすると、動画の位置にスクロールします。\n 市場を見てからプレイヤーに戻りたい時などに便利',
values: {'する': true, 'しない': false}},
{title: 'マウスのボタン+ホイールでどこでも音量調整', varName: 'mouseClickWheelVolume',
description: 'とっさに音量を変えたい時に便利',
values: {'左ボタン+ホイール': 1, '右ボタン+ホイール': 2, '使わない': 0}},
{title: '停止/再生',                            varName: 'shortcutTogglePlay',        type: 'keyInput'},
{title: 'とりあえずマイリスト登録',       varName: 'shortcutDefMylist',          type: 'keyInput'},
{title: 'マイリスト登録',                 varName: 'shortcutMylist',             type: 'keyInput',
description: '右下で選択中のマイリストに登録'},
{title: 'とりあえずマイリストを開く',           varName: 'shortcutOpenDefMylist',      type: 'keyInput'},
{title: '動画投稿者の関連動画を開く',           varName: 'shortcutShowOtherVideo',     type: 'keyInput'},
{title: '検索画面を開く',                       varName: 'shortcutOpenSearch',         type: 'keyInput'},
{title: '関連動画(オススメ)を開く',             varName: 'shortcutOpenRecommend',      type: 'keyInput'},
{title: 'コメント表示ON/OFF',                   varName: 'shortcutCommentVisibility',  type: 'keyInput'},
{title: 'プレイヤーの位置までスクロール',       varName: 'shortcutScrollToNicoPlayer', type: 'keyInput'},
{title: 'ミュート',                             varName: 'shortcutMute',               type: 'keyInput'},
{title: 'コメントの背面表示ON/FF',              varName: 'shortcutDeepenedComment',    type: 'keyInput'},
{title: 'ハードウェアアクセラレーションON/FF',  varName: 'shortcutToggleStageVideo',   type: 'keyInput'},
{title: 'その他2(一発ネタ系)', description: 'いつのまにか消えるかもしれません', className: 'shortcut'},
{title: 'テレビちゃんメニュー内にランダム画像(左上)表示', varName: 'hidariue',
values: {'する': true, 'しない': false}},
{title: 'ゆっくり再生(スロー再生)ボタンを表示', varName: 'enableYukkuriPlayButton',
values: {'する': true, 'しない': false}},
{title: '実験中の設定', className: 'forDebug'},
{title: '動画のロードを待たずに初期化する', varName: 'initializeImmediately',
values: {'する': true, 'しない': false}},
//      {title: 'プレイリスト消えないモード(※実験中)',       varName: 'hashPlaylistMode', debugOnly: true, reload: true,
//        values: {'有効(連続再生中のみ)': 1, '有効(常時)': 2, '無効': 0}},
];
var listener = [];
function dispatchEvent(name, value, lastValue) {
for (var i = 0; i < listener.length; i++) {
(listener[i])(name, value, lastValue);
}
}
pt.createPanelDom = function() {
if ($panel === null) {
$panel = jQuery([
'<div id="watchItLaterConfigPanel">',
'<div class="head"><button class="closeButton" title="閉じる">▲</button><h2>WatchItLaterの設定</h2>(※)のつく項目は、リロード後に反映されます</div>',
'<div class="inner"></div></div>'
].join(''));
$panel.on('click', function(e) { e.stopPropagation(); });
var scrollTo = function() {
var $target = this;
var isOpen = $target.parent().toggleClass('open').hasClass('open');
if (isOpen) {
setTimeout(function() {
var $inner = $('#watchItLaterConfigPanel .inner');
$inner.animate({
scrollTop: $inner.scrollTop() + $target.parent().position().top - 50
}, 400);
}, 200);
}
};
var $ul = null, $inner = $panel.find('.inner'), $item; //$panel.find('ul'), $item;
for (var i = 0, len = menus.length; i < len; i++) {
if (menus[i].varName) {
$item = this.createMenuItem(menus[i]);
} else {
if (menus[i].description) {
$item = $('<li class="section ' +menus[i].className + '"><div><span>'+ menus[i].title + '</span><span class="description">'+ menus[i].description + '</span></div></li>');
} else {
$item = $('<li class="section ' +menus[i].className + '"><div><span>'+ menus[i].title + '</span></div></li>');
}
if ($ul) $inner.append($ul);
$ul =$('<ul class="sectionContainer"/>').addClass(menus[i].className + 'Container');
$item.click($.proxy(scrollTo, $item));
}
$item.toggleClass('debugOnly', menus[i].debugOnly === true).toggleClass('reload', menus[i].reload === true);
if ($ul) $ul.append($item);
}
if ($ul) $inner.append($ul);
$panel.toggleClass('debugMode', conf.debugMode);
var $bottom = jQuery('<div class="foot"></div>'), self = this;
$panel.append($bottom);
$panel.find('.closeButton').click(function() {
self.close();
});
if ($shadow === null) {
$shadow = $('<div id="watchItLaterConfigPanelShadow" /><div id="watchItLaterConfigPanelShadowTop"/><div id="watchItLaterConfigPanelOverShadow"/>');
}
}
};
pt.refresh = function() {
var isVisible = $panel.hasClass('open');
$panel.remove().empty();
$panel = null;
this.createPanelDom();
if (isVisible) { $panel.show(); }
};
pt.createMenuItem = function(menu) {
if (menu.type === 'text') {
return this.createTextMenuItem(menu);
} else
if (menu.type === 'keyInput') {
return this.createKeyInputMenuItem(menu);
} else {
return this.createRadioMenuItem(menu);
}
};
pt.createRadioMenuItem = function(menu) {
var title = menu.title, varName = menu.varName, values = menu.values;
var $menu = jQuery('<li><p class="title">' + title + '</p></li>');
if (menu.className) { $menu.addClass(menu.className);}
if (menu.description) { $menu.attr('title', menu.description); }
var currentValue = conf.getValue(varName);
$menu.addClass(menu.varName);
if (menu.addClass) { $panel.addClass(menu.varName + '_' + currentValue);}
for (var k in values) {
var v = values[k];
var $label = jQuery('<label></label>');
var $chk = jQuery('<input>');
$chk.attr({type: 'radio', name: varName, value: JSON.stringify(v)});
if (currentValue === v) {
$chk.prop('checked', 'checked');
}
$chk.click(function() {
var newValue = JSON.parse(this.value), oldValue = conf.getValue(varName);
if (oldValue !== newValue) {
if (menu.addClass) {
$panel.removeClass(menu.varName + '_' + oldValue).addClass(menu.varName + '_' + newValue);
}
conf.setValue(menu.varName, newValue);
if (typeof menu.onchange === 'function') {
menu.onchange(newValue, oldValue);
}
dispatchEvent(menu.varName, newValue, oldValue);
}
});
$label.append($chk).append(jQuery('<span>' + k + '</span>'));
$menu.append($label);
}
return $menu;
};
pt.createTextMenuItem = function(menu) {
var title = menu.title, varName = menu.varName;
var $menu = jQuery('<li><p class="title">' + title + '</p></li>');
if (menu.className) { $menu.addClass(menu.className);}
if (menu.description) { $menu.attr('title', menu.description); }
var currentValue = conf.getValue(varName);
var $input = jQuery('<input type="text" />');
$menu.addClass(menu.varName);
if (menu.addClass) { $panel.addClass(menu.varName + '_' + currentValue);}
$input.val(currentValue);
$input.change(function() {
var newValue = $input.val(), oldValue = conf.getValue(varName);
if (oldValue !== newValue) {
conf.setValue(varName, newValue);
if (typeof menu.onchange === 'function') {
menu.onchange(newValue, oldValue);
}
dispatchEvent(menu.varName, newValue, oldValue);
}
});
$menu.append($input);
return $menu;
};
pt.createKeyInputMenuItem = function(menu) {
var title = menu.title, varName = menu.varName;
var currentValue = conf.getValue(varName), currentKey = currentValue.char;
function update() {
var newValue = {char: $sel.val(), ctrl: $menu.hasClass('ctrl'), alt: $menu.hasClass('alt'), shift: $menu.hasClass('shift'), enable: $menu.hasClass('enable')};
conf.setValue(varName, newValue);
if (typeof menu.onchange === 'function') {
menu.onchange(newValue);
}
dispatchEvent(menu.varName, newValue, conf.getValue(varName));
}
var $menu = jQuery('<li class="shortcutSetting"><p class="title">' + title + '</p></li>');
var sel = ['<select>'], $sel;
for (var v = 48; v <= 90; v++) {
if (v >= 0x3c && v <= 0x3f) continue;
var c = String.fromCharCode(v);
var op = ['<option value="', c, '">', c, '</option>'  ].join('');
sel.push(op);
}
sel.push('</select>');
$sel = jQuery(sel.join(''));
var $meta = jQuery('<span class="enable" data-meta="enable">有効</span><span class="ctrl" data-meta="ctrl">ctrl</span><span class="alt" data-meta="alt">alt</span><span class="shift" data-meta="shift">shift</span>').on('click', function(e) {
var meta = jQuery(e.target).attr('data-meta');
$menu.toggleClass(meta);
update();
});
$sel.change(update);
$menu.toggleClass('enable', currentValue.enable).toggleClass('ctrl', currentValue.ctrl).toggleClass('alt', currentValue.alt).toggleClass('shift', currentValue.shift);
$sel.val(currentKey);
if (menu.className) { $menu.addClass(menu.className);}
if (menu.description) { $menu.attr('title', menu.description); }
$menu.append(jQuery('<span/>').append($meta).append($sel));
return $menu;
};
pt.toggleOpenSection = function(sectionName, toggle) {
$('#watchItLaterConfigPanel .'+ sectionName + 'Container').toggleClass('open', toggle);
$('#watchItLaterConfigPanel .inner').scrollTop($('#watchItLaterConfigPanel .' + sectionName).position().top - 50);
};
pt.addChangeEventListener = function(callback) {
listener.push(callback);
};
pt.open = function()  {
$('body').append($shadow).append($panel);
setTimeout(function() {
$shadow.addClass('open'); $panel.addClass('open');
}, 50);
setTimeout(function() {
if (WatchController.isFullScreen()) {
pt.toggleOpenSection('fullScreen', true);
} else
if (WatchController.isSearchMode()) {
pt.toggleOpenSection('videoExplorer', true);
}
}, 1000);
};
pt.close = function() {
$shadow.removeClass('open'); $panel.removeClass('open');
setTimeout(function() {
$shadow.detach(); $panel.detach();
}, 800);
};
pt.toggle = function() {
this.createPanelDom();
if ($panel.hasClass('open')) {
this.close();
} else {
this.open();
}
};
return pt;
})(jQuery, conf, w);
/**
* 通信用
*/
window.WatchItLater = {
config: {
get: function(varName) {
return conf.getValue(varName);
},
set: function(varName, value) {
conf.setValue(varName, value);
},
open: function() {
ConfigPanel.open();
}
},
loader: {},
debug: {},
init: {},
test: {
assert: function(v, m) {
if (v === true) {
window.console.log('%c OK: ',  'color: black; background: lime;',  m);
} else {
window.console.log('%cFail: ', 'color: white; background: red;',   m);
throw {message: 'Fail'};
}
},
expect: function(a) {
try {
var assert = window.WatchItLater.test.assert, exp = {
toBeTrue:    function(   desc) { assert(a === true   , desc); },
toBeFalse:   function(   desc) { assert(a === false  , desc); },
toEqual:     function(b, desc) { assert(a === b      , desc); },
toBeNull:    function(   desc) { assert(a === null   , desc); },
toBeNotNull: function(   desc) { assert(a !== null   , desc); },
toBeDefined: function(   desc) { assert(a !== void 0 , desc); },
toBeTruthy:  function(   desc) { assert(a ? true : false, desc); }
};
return exp;
} catch(e) {
window.console.log('%c', a);
}
},
spec: {},
run: function(name) {
var def = (new $.Deferred()), promise = def.promise();
var con = function(name) {
return function() {
var d = new $.Deferred();
setTimeout(function() {
window.console.log('%c RUN: ' + name, 'background: #8ff;');
d.resolve();
}, 100);
return d.promise();
};
};
var wrap = function(self, name) {
return function() {
var d = new $.Deferred();
setTimeout(function() {
try {
$.proxy(self.spec[name], self)(d);
} catch (e) {
window.console.log(e);
d.reject();
}
}, 0);
return d.promise();
};
};
var onFail = function(e) {
window.console.log('%c fail : ','background: red;', e);
};
if (name) {
promise = promise.then(con(name)).then(wrap(this, name), onFail);
} else {
for(var v in this.spec) {
if (!v.match(/^test/)) continue;
promise = promise.then(con(v)) .then(wrap(this,    v), onFail);
}
}
promise.then(
function() { window.console.log('%cテスト完了', 'background: #8ff'); },
function() { window.console.log('%cテスト失敗', 'background: #f00'); }
);
def.resolve();
}
}
};
//  w.WatchItLater = window.WatchItLater;
var EventDispatcher = (function(conf) {
var events = {};
function addEventListener(name, callback) {
name = name.toLowerCase();
if (!events[name]) {
events[name] = [];
}
events[name].push(callback);
}
function _dispatch(name) {
name = name.toLowerCase();
if (!events[name]) { return; }
var e = events[name];
for (var i =0, len = e.length; i < len; i++) {
try {
e[i].apply(null, Array.prototype.slice.call(arguments, 1));
} catch (ex) {
console.log('%c' + name, 'background:red; color: white;', i, e[i], ex);
}
}
}
function dispatch(name) {
console.log('%cevent:', 'background: blue; color: white;', name);//, arguments);
_dispatch.apply(null, arguments);
}
return {
addEventListener: addEventListener,
dispatch: dispatch,
_dispatch: _dispatch // コンソール汚したくない用
};
})(conf);
window.WatchItLater.event = EventDispatcher;
/*
* 通算視聴回数をカウント。 カウントしても意味はないけど、どれだけ無駄な時間を費やしたかを知りたくて実装。
*/
var WatchCounter = (function(conf, w) {
var key = 'watchItLater_watchCounter';
function get() {
return JSON.parse(w.localStorage.getItem(key));
}
function add() {
var v = get() + 1;
w.localStorage.setItem(key, JSON.stringify(v));
console.log('%cwatchCounter: %c%d', 'color: orange;', 'font-weight: bolder;', v);
return v;
}
var self = {
get: get,
add: add
};
return self;
})(conf, w);
window.WatchItLater.counter = WatchCounter;
/**
*  動画タグ取得とポップアップ
*
*/
var VideoTags = (function(conf, w){
var host = location.host.replace(/^([\w\d]+)\./, 'www.');
var pt = function(){};
var lastPopup = null;
pt.get = function(watchId, callback) {
var _get = function(watchId, callback) {
var url = 'http://' + host + '/tag_edit/' + watchId + '/?res_type=json&cmd=tags';
//http://www.nicovideo.jp/tag_edit/sm9/?res_type=json&cmd=tags
var req = {
method: 'GET',
url: url,
onload: function(resp) {
var r###lt = JSON.parse(resp.responseText);
if (typeof callback === 'function') callback(r###lt.status, r###lt);
}
};
httpRequest(req);
};
WatchController.getTid2Vid(watchId, function(videoId) {
_get(videoId, callback);
});
};
pt.hidePopup = function() {
if (lastPopup) {
lastPopup.style.display = 'none';
}
};
var uniq = null, $history = null, popupContainer = null;
pt.popupItems = function(watchId, baseX, baseY) {
var self = this;
popupContainer.innerHTML = '';
this.get(watchId, function(status, resp) {
if (status === 'ok') {
var tags = resp.tags;
self.hidePopup();
if (tags.length > 0) {
lastPopup = createPopup(tags, baseX, baseY);
} else {
Popup.show('この動画のタグはありません');
}
} else {
Popup.alert(resp.error_message);
}
});
function getBodyMarginLeft() {
try {
var cp = document.defaultView.getComputedStyle(document.body, null);
var ml = cp.getPropertyValue('margin-left');
if (ml.match(/^(\d+)px/)) {
return parseInt(RegExp.$1, 10);
}
return 0;
} catch (e) {
window.console.error('getBodyMarginLeft Exception!', e);
return 0;
}
}
function createPopup(tags, baseX, baseY) {
var popup = createDOM(tags, baseX, baseY);
popupContainer.appendChild(popup);
popup.style.right = null;
popup.style.left = baseX + 'px';
popup.style.top = Math.max(baseY - popup.offsetHeight, 0, document.body.scrollTop, document.documentElement.scrollTop) + 'px';
if (popup.offsetLeft + popup.offsetWidth > document.body.clientWidth + getBodyMarginLeft()) {
popup.style.left = null;
popup.style.right = 0;
}
return popup;
}
function createDOM(tags) {
var items = document.createElement('ul');
for (var i = 0, len = tags.length; i < len; i++) {
items.appendChild(createItemDOM(tags[i]));
}
var popup = createPopupDOM();
popup.appendChild(items);
return popup;
}
function createPopupDOM() {
var popup = document.createElement('div');
popup.className        = 'tagItemsPopup popupMenu';
popup.addEventListener('click', createPopupOnClick(), false);
return popup;
}
function createPopupOnClick() {
return function(e) {
if (e.button !== 0 || e.shiftKey || e.ctrlKey || e.altKey || e.target.className === 'icon' || e.target.tagName === 'A') {
return;
}
this.style.display = 'none';
e.preventDefault();
e.stopPropagation();
};
}
function appendTagHistory(dom, text, dic) {
var $ = w.$;
if (uniq === null) {
uniq = {};
$history = $('<div class="tagSearchHistory"><h3 class="title">タグ検索履歴</h3></div>');
$history.css({width: $('.videoExplorerMenu').width() - 8, maxHeight: '300px', overflowY: 'auto'});
$('.videoExplorerMenu').append($history);
}
if (!uniq[text]) {
var a = $(dom).clone().css({marginRight: '8px', fontSize: '80%'}).click(Util.Closure.openNicoSearch(text));
dic.style.marginRight = '0';
$history.find('.title').after(a).after(dic);
}
uniq[text] = 1;
}
function createItemDOM(tag) {
var text = tag.tag;
var li  = document.createElement('li');
li.className = 'popupTagItem';
text = text.replace(/&amp;/g, '&');
// 大百科アイコン
var dic = createDicIconDOM(tag, text);
li.appendChild(dic);
// 新検索(search.nicovideo.jp)へのリンク
var newSearchIcon = createNewSearchIconDOM(tag, text);
li.appendChild(newSearchIcon);
// 本文リンク
var a = document.createElement('a');
a.appendChild(document.createTextNode(text));
var href = text;
if (conf.defaultSearchOption && conf.defaultSearchOption !== '' && !text.match(/(sm|nm|so)\d+/)) {
href += ' ' + conf.defaultSearchOption;
}
//var sortOrder = '?sort=' + conf.searchSortType + '&order=' + conf.searchSortOrder;
a.href = 'http://' + host + '/tag/' + encodeURIComponent(href);
a.addEventListener('click', createItemOnClick(text, dic), false);
li.appendChild(a);
return li;
}
function createItemOnClick(text, dic) {
return function(e) {
if (e.button !== 0 || e.metaKey) return;
if (w.WatchJsApi) {
WatchController.nicoSearch(text, 'tag');
e.preventDefault();
appendTagHistory(this, text, dic);
}
return false;
};
}
function createNewSearchIconDOM(tag, text) {
var link = document.createElement('a');
link.className = 'newsearch';
link.title     = 'niconico新検索で開く';
// TODO: パラメータの対応表作ってあわせる
var newSortOrder = '';
link.href = 'http://search.nicovideo.jp/video/search/' + encodeURIComponent(text) + newSortOrder;
if (location.host !== 'search.nicovdieo.jp') {
link.target = '_blank';
}
var icon = document.createElement('img');
icon.className = 'icon';
icon.src = 'http://uni.res.nimg.jp/img/favicon.ico';
link.appendChild(icon);
return link;
}
function createDicIconDOM(tag, text) {
var dic = document.createElement('a');
dic.className = 'nicodic';
dic.href = 'http://dic.nicovideo.jp/a/' + encodeURIComponent(text);
dic.target = '_blank';
var icon = document.createElement('img');
icon.className = 'icon';
icon.src = tag.dic ? 'http://live.nicovideo.jp/img/2012/watch/tag_icon002.png' : 'http://live.nicovideo.jp/img/2012/watch/tag_icon003.png';
dic.appendChild(icon);
return dic;
}
};
popupContainer = document.createElement('div');
popupContainer.id = 'videoTagPopupContainer';
document.body.appendChild(popupContainer);
return pt;
})(conf, w);
/**
*  マイリスト登録API
*
*  (9)の頃は、iframeを作ってその中にマイリスト登録のポップアップウィンドウを開くという手抜きを行っていたが、
*  ポップアップウィンドウは評判が悪いし、そのうち廃止されるだろうなと思うので、
*  真面目にAPIを叩くようにした。 (マイリストの新規作成機能は省略)
*
*  …と思っていたのだが、(9)からQになった今でもポップアップウィンドウは廃止されないようだ。
*/
var Mylist = window.WatchItLater.mylist = (function(){
var mylistlist = [];
var initialized = false;
var deflistItems = [], mylistItems = {};
var host = location.host.replace(/^([\w\d]+)\./, 'www.');
var token = '';//
function Mylist() {
this.initialize();
}
function getToken() {
if (!isNativeGM && host !== location.host) return null; //
var _token = (w.NicoAPI && w.NicoAPI.token) ? w.NicoAPI.token : '';
if (w.NicoAPI && w.NicoAPI.token) {
return w.NicoAPI.token;
} else
if (w.WatchJsApi) {
var watchInfoModel = require('watchapp/model/WatchInfoModel').getInstance();
watchInfoModel.addEventListener('reset', function(watchInfoModel) {
token = watchInfoModel.csrfToken;
});
if (watchInfoModel.initialized) {
return watchInfoModel.csrfToken;
} else {
var dc = JSON.parse($("#watchAPIDataContainer").text());
return dc.flashvars.csrfToken;
}
} else
if (_token === null && w.FavMylist && w.FavMylist.csrf_token) {
_token = w.FavMylist.csrf_token;
}
if (_token !== '') {
return _token;
}
var url = 'http://' + host + '/mylist_add/video/sm9'; // マイリスト登録ウィンドウから強引にtoken取得
//      var url = 'http://' + host + '/my/mylist'; // マイリスト登録ウィンドウから強引にtoken取得
httpRequest({
url: url,
onload: function(resp) {
//console.log(116, resp.responseText);
var r###lt = resp.responseText;
if (r###lt.match(/NicoAPI\.token *= *["']([a-z0-9\-]+)["'];/)) {
console.log('NicoAPI.token=', token);
token = RegExp.$1;
} else {
console.log('%cNicoAPI.token Not Found', 'background: red;');
}
}
});
return _token;
}
var pt = Mylist.prototype, events = {defMylistUpdate: [], mylistUpdate: []};
function dispatchEvent(name) {
var e = events[name];
for (var i =0, len = e.length; i < len; i++) {
e[i].apply(null, Array.prototype.slice.call(arguments, 1));
}
}
pt.onDefMylistUpdate = function(callback) {
events.defMylistUpdate.push(callback);
};
pt.onMylistUpdate = function(callback) {
events.mylistUpdate.push(callback);
};
pt.setCsrfToken = function(csrfToken) {
token = csrfToken;
};
pt.getUserId = function() {
if (document.cookie.match(/user_session_(\d+)/)) {
return RegExp.$1;
} else {
return false;
}
};
var onInitialized = [];
pt.initialize = function() {
if (initialized) return;
var uid = this.getUserId();
if (!uid) {
return;
}
if (!isNativeGM && host !== location.host) {
initialized = true;
return;
}
token = getToken();
//var url = 'http://' + host + '/api/watch/uservideo?user_id=' + uid;
var url = 'http://' + host + '/api/mylistgroup/list';
httpRequest({
url: url,
onload: function(resp) {
var r###lt = JSON.parse(resp.responseText);
if (r###lt.status === "ok" && r###lt.mylistgroup) {
mylistlist = r###lt.mylistgroup;
initialized = true;
for (var i = 0; i < onInitialized.length; i++) {
onInitialized[i](mylistlist.concat());
}
}
}
});
this.reloadDeflist();
};
pt.loadMylistList = function(callback) {
if (initialized) {
setTimeout(function() { callback(mylistlist.concat()); }, 0);
} else {
onInitialized.push(callback);
}
};
pt.isMine = function(id) {
if (!initialized) { return false; }
for (var i = 0, len = mylistlist.length; i < len; i++) {
if (mylistlist[i].id == id) { return true; }
}
return false;
};
pt.reloadDeflist = function(callback) {
var url = 'http://' + host + '/api/deflist/list';
httpRequest({
url: url,
onload: function(resp) {
try {
JSON.parse(resp.responseText);
} catch (e) {
window.console.log(e);
window.console.log(resp.responseText);
}
if (!resp.responseText) return;
var r###lt = JSON.parse(resp.responseText);
if (r###lt.status === "ok" && r###lt.mylistitem) {
deflistItems = r###lt.mylistitem;
if (typeof callback === "function") callback(deflistItems);
}
}
});
};
pt.loadMylist = function(groupId, callback) {
if (mylistItems[groupId]) {
setTimeout(function() {callback(mylistItems[groupId]); }, 0);
return;
}
var url = 'http://' + host + '/api/mylist/list?group_id=' + groupId;
httpRequest({
url: url,
onload: function(resp) {
var r###lt = JSON.parse(resp.responseText);
if (r###lt.status === "ok" && r###lt.mylistitem) {
mylistItems[groupId] = r###lt.mylistitem;
if (typeof callback === "function") callback(r###lt.mylistitem);
}
}
});
};
pt.clearMylistCache = function(groupId) {
delete mylistItems[groupId];
};
pt.reloadMylist = function(groupId, callback) {
this.clearMylistCache(groupId);
return this.loadMylist(groupId, callback);
};
pt.findDeflistByWatchId = function(watchId) {
//      if (/^[0-9]+$/.test(watchId)) return watchId; // スレッドIDが来た
for (var i = 0, len = deflistItems.length; i < len; i++) {
var item = deflistItems[i], wid = item.item_data.watch_id;
if (wid == watchId) return item;
}
return null;
};
pt.findMylistByWatchId = function(watchId, groupId) {
//      if (/^[0-9]+$/.test(watchId)) return watchId; // スレッドIDが来た
var items = mylistItems[groupId];
if (!items) { return null; }
for (var i = 0, len = items.length; i < len; i++) {
var item = items[i], wid = item.item_data.watch_id;
if (wid == watchId) return item;
}
return null;
};
// おもに参考にしたページ
// http://uni.res.nimg.jp/js/nicoapi.js
// http://d.hatena.ne.jp/lolloo-htn/20110115/1295105845
// http://d.hatena.ne.jp/aTaGo/20100811/1281552243
pt.deleteDeflistItem = function(watchId, callback) {
var item = this.findDeflistByWatchId(watchId);
if (!item) return false;
var item_id = item.item_id;
var url = 'http://' + host + '/api/deflist/delete';
var data = 'id_list[0][]=' + item_id + '&token=' + token;
var req = {
method: 'POST',
data: data,
headers: {'Content-Type': 'application/x-www-form-urlencoded'}, // これを忘れて小一時間はまった
url: url,
onload: function(resp) {
var r###lt = JSON.parse(resp.responseText);
if (typeof callback === "function") callback(r###lt.status, r###lt);
if (jQuery) {
deflistItems = jQuery.grep(deflistItems, function(item) {
return item.item_data.watch_id !== watchId;
});
}
dispatchEvent('defMylistUpdate');
}
};
httpRequest(req);
return true;
};
pt.addDeflistItem = function(watchId, callback, description) {
var url = 'http://' + host + '/api/deflist/add';
// 例えば、とりマイの300番目に登録済みだった場合に「登録済みです」と言われても探すのがダルいし、
// 他の動画を追加していけば、そのうち押し出されて消えてしまう。
// なので、重複時にエラーを出すのではなく、「消してから追加」することによって先頭に持ってくる。
// 「重複してたら先頭に持ってきて欲しいな~」って要望掲示板にこっそり書いたりしたけど相手にされないので自分で実装した。
var data = "item_id=" + watchId + "&token=" + token, replaced = true;
if (description) {
data += '&description='+ encodeURIComponent(description);
}
var _add = function(status, resp) {
var req = {
method: 'POST',
data: data,
url: url,
headers: {'Content-Type': 'application/x-www-form-urlencoded' }, // これを忘れて小一時間はまった
onload: function(resp) {
var r###lt = JSON.parse(resp.responseText);
if (typeof callback === "function") callback(r###lt.status, r###lt, replaced);
}
};
httpRequest(req);
};
// とりあえずマイリストにある場合はdeleteDeflistItem()のcallbackで追加、ない場合は即時追加
if (!this.deleteDeflistItem(watchId, _add)) {
replaced = false;
_add();
dispatchEvent('defMylistUpdate');
}
};
pt.addMylistItem = function(watchId, groupId, callback, description) {
var self = this;
var url = 'http://' + host + '/api/mylist/add';
var data = ['item_id=', watchId,
'&group_id=', groupId,
'&item_type=', 0, // video=0 seiga=5
'&description=', (typeof description === 'string') ? encodeURIComponent(description) : '',
'&token=', token
].join('');
// 普通のマイリストのほうは重複しても「消してから追加」という処理を行っていない。
// とりあえずマイリストと違って登録の順番に意味があるのと、
// 古いのが押し出される心配がないため。
var _add = function() {
var req = {
method: 'POST',
data: data,
url: url,
headers: {'Content-Type': 'application/x-www-form-urlencoded' },
onload: function(resp) {
var r###lt = JSON.parse(resp.responseText);
if (typeof callback === "function") callback(r###lt.status, r###lt);
if (r###lt.status === 'ok') {
dispatchEvent('mylistUpdate', {action: 'add', groupId: groupId, watchId: watchId});
EventDispatcher.dispatch('onMylistItemAdded', groupId, watchId);
self.clearMylistCache(groupId);
}
},
error: function() {
Popup.alert('ネットワークエラー');
}
};
httpRequest(req);
};
// 普通のマイリストに入れたら、とりあえずマイリストからは削除(≒移動)
if (!this.deleteDeflistItem(watchId, _add)) _add();
};
pt.updateDeflistItem = function(watchId, callback, description) {
var self = this;
var item = self.findDeflistByWatchId(watchId);
if (!item) {
Popup.alert('マイリスト中に該当する動画がみつかりませんでした');
return;
}
var
itemId = item.item_id,
url = 'http://' + host + '/api/deflist/update',
data = ['item_id=', itemId,
'&item_type=', 0, // video=0 seiga=5
'&description=', (typeof description === 'string') ? encodeURIComponent(description) : '',
'&token=', token
].join(''),
req = {
method: 'POST',
data: data,
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
url: url,
onload: function(resp) {
var r###lt = JSON.parse(resp.responseText);
if (r###lt.status === 'ok') {
if (typeof callback === "function") callback(r###lt.status, r###lt);
dispatchEvent('deflistUpdate', {action: 'update', watchId: watchId});
EventDispatcher.dispatch('onDeflistItemUpdated', watchId);
}
},
error: function() {
Popup.alert('ネットワークエラー');
}
};
httpRequest(req);
};
pt.updateMylistItem = function(watchId, groupId, callback, description) {
var self = this;
this.loadMylist(groupId, function() {
var item = self.findMylistByWatchId(watchId, groupId);
if (!item) {
Popup.alert('マイリスト中に該当する動画がみつかりませんでした');
return;
}
var
itemId = item.item_id,
url = 'http://' + host + '/api/mylist/update',
data = ['item_id=', itemId,
'&group_id=', groupId,
'&item_type=', 0, // video=0 seiga=5
'&description=', (typeof description === 'string') ? encodeURIComponent(description) : '',
'&token=', token
].join(''),
req = {
method: 'POST',
data: data,
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
url: url,
onload: function(resp) {
var r###lt = JSON.parse(resp.responseText);
if (r###lt.status === 'ok') {
if (typeof callback === "function") callback(r###lt.status, r###lt);
dispatchEvent('mylistUpdate', {action: 'update', groupId: groupId, watchId: watchId});
EventDispatcher.dispatch('onMylistItemUpdated', groupId, watchId);
}
},
error: function() {
Popup.alert('ネットワークエラー');
}
};
httpRequest(req);
});
};
pt.deleteMylistItem = function(watchId, groupId, callback) {
var self = this;
this.loadMylist(groupId, function() {
var item = self.findMylistByWatchId(watchId, groupId);
if (!item) {
Popup.alert('マイリスト中に該当する動画がみつかりませんでした');
return;
}
var
item_id = item.item_id,
url = 'http://' + host + '/api/mylist/delete',
data = [
'id_list[0][]=', item_id,
'&group_id=',    groupId,
'&token=',       token
].join(''),
req = {
method: 'POST',
data: data,
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
url: url,
onload: function(resp) {
var r###lt = JSON.parse(resp.responseText);
if (r###lt.status === 'ok') {
if (typeof callback === "function") callback(r###lt.status, r###lt);
dispatchEvent('mylistUpdate', {action: 'delete', groupId: groupId, watchId: watchId});
EventDispatcher.dispatch('onMylistItemDeleted', groupId, watchId);
}
},
error: function() {
Popup.alert('ネットワークエラー');
}
};
httpRequest(req);
});
};
/**
*  マイリスト登録パネルを返す
*/
pt.getPanel = function(watchId, videoId) {
if (isNativeGM || host === location.host) {
return this.getNativePanel(watchId, videoId);
} else {
return this.getIframePanel(watchId, videoId);
}
};
pt.getNativePanel = function(watchId, videoId) {
var self = this;
var _watchId = watchId, _videoId = videoId || watchId;
var body = document.createElement('div');
var mylistListPopup = null;
body.className = 'mylistPopupPanel deflistSelected';
var nobr = document.createElement('nobr');
body.appendChild(nobr);
var extArea = document.createElement('span');
var isWatchPage = (window.PlayerApp) ? true : false;
var addDeflist = function(watchId, description) {
self.addDeflistItem(watchId, function(status, r###lt, replaced) {
self.reloadDeflist();
if (status !== 'ok') {
Popup.alert('とりあえずマイリストへの登録に失敗: ' + r###lt.error.description);
} else {
var torimai = '<a href="/my/mylist">とりあえずマイリスト</a>';
Popup.show(
torimai +
(replaced ? 'の先頭に移動しました' : 'に登録しました')
);
}
}, description);
};
var addMylist = function(watchId, mylistId, mylistName, description) {
self.addMylistItem(watchId, mylistId, function(status, r###lt) {
self.reloadDeflist();
if (status === 'ok') {
Popup.show( '<a href="/my/mylist/#/' + mylistId + '">' + mylistName + '</a>に登録しました');
} else {
Popup.alert(mylistName + 'への登録に失敗: ' + r###lt.error.description);
}
}, description);
};
var setButtonStyleUpdating = function(btn) {
btn.style.opacity = 0.5;
btn.style.cursor = 'pointer';
btn.disabled = true;
window.setTimeout(function() {
btn.disabled = false;
btn.style.opacity = 1;
btn.style.cursor = 'pointer';
btn = null;
}, 1000);
};
var onMylistListClick = function(mylistId, mylistName, type) {
if (type === 'icon') {
if (window.WatchJsApi) {
if (mylistId === 'default') {
WatchController.showDeflist();
} else {
WatchController.showMylist(mylistId);
}
} else {
location.href = 'http://' + host +  '/my/mylist/#/' + mylistId.replace('default','home');
}
return;
}
if (mylistId === 'default') {
addDeflist(_watchId);
} else {
addMylist(_watchId, mylistId, mylistName);
}
};
body.watchId = function(w, v) {
if (w) {
_watchId = w;
_videoId = v || w;
var isThreadId = (/^[0-9]+$/.test(w));
deleteDef.disabled = false;
if (self.findDeflistByWatchId(w)) {
deleteDef.style.display = '';
} else {
deleteDef.style.display = 'none';
}
if (!isWatchPage && isThreadId) {
tagBtn.style.display = 'none'; // スレッドIDから動画IDを取る手段がないためタグ取得が難しい
} else {
tagBtn.style.display = '';
}
if (newTabLink) {
newTabLink.href = 'http://nico.ms/' + _watchId; // QWatchに乗っ取られないようにnico.msをかます(せこい)
}
if (mylistListPopup) {
mylistListPopup.hide();
}
return body;
}
return _watchId;
};
body.show = function() {
body.style.display = '';
if (mylistListPopup) {
mylistListPopup.hide();
}
};
body.hide = function() {
body.style.display = 'none';
if (mylistListPopup) {
mylistListPopup.hide();
}
};
function createSelector() {
var sel = document.createElement('select');
var lastSelect = 0;
sel.className = 'mylistSelect';
var appendO = function(sel, text, value) {
var opt = document.createElement('option');
opt.appendChild(document.createTextNode(text));
opt.value = value;
sel.appendChild(opt);
return opt;
},
createOptions = function() {
for (var i = 0, len = mylistlist.length; i < len; i++) {
var mylist = mylistlist[i];
appendO(sel, (i + 1).toString(36) + ':' +  mylist.name, mylist.id);
}
},
onSelect = function() {
// jQueryは全てのページにあるわけではないので気をつける。忘れると原宿が死ぬ
if (sel.selectedIndex === 0) {
body.className = body.className.replace('mylistSelected', 'deflistSelected');
} else {
lastSelect = sel.selectedIndex;
body.className = body.className.replace('deflistSelected', 'mylistSelected');
}
},
selectDeflist = function() {
sel.selectedIndex = 0;
onSelect();
},
onContextMenu = function(e) {
e.preventDefault();
e.stopPropagation();
if (lastSelect === 0) return;
if (sel.selectedIndex === 0) {
sel.selectedIndex = lastSelect;
} else {
sel.selectedIndex = 0;
}
onSelect();
};
appendO(sel, '0:とりマイ', 'default');
sel.selectedIndex = 0;
window.setTimeout(createOptions, initialized ? 0 : 3000);
sel.addEventListener('change', onSelect, false);
sel.addEventListener('contextmenu', onContextMenu, false);
body.addEventListener('dblclick', selectDeflist, false);
return sel;
}
function creat###bmitButton() {
var btn = document.createElement('button');
btn.appendChild(document.createTextNode('my'));
btn.className = 'mylistAdd';
btn.title = 'マイリストに追加\n(ボタンを右クリックで詳細メニュー)';
var callMylistListPopup = function() {
if (!mylistListPopup) {
mylistListPopup = new MylistListPopup(mylistlist, onMylistListClick);
}
mylistListPopup.toggle(btn, _watchId);
};
btn.addEventListener('contextmenu', function(e) {
if (jQuery) {
e.preventDefault();
e.stopPropagation();
callMylistListPopup();
}
});
btn.addEventListener('click', function(e) {
var description = null;
if (e.shiftKey) {
description = prompt('マイリストコメントの入力');
if (!description) return;
}
setButtonStyleUpdating(btn);
var mylistId = sel.value, name = sel.options[sel.selectedIndex].textContent;
if (mylistId === 'default') {
addDeflist(_watchId, description);
} else {
addMylist(_watchId, mylistId, name, description);
}
} ,false);
return btn;
}
function createDeleteDeflistItemButton() {
var btn = document.createElement('button');
btn.appendChild(document.createTextNode('×'));
btn.className = 'deflistRemove';
btn.title = 'とりあえずマイリストから外す';
btn.addEventListener('click', function() {
setButtonStyleUpdating(btn);
self.deleteDeflistItem(_watchId, function(status, r###lt) {
self.reloadDeflist();
btn.style.display = 'none';
if (status !== "ok") {
Popup.alert('とりあえずマイリストから削除に失敗: ' + r###lt.error.description);
} else {
Popup.show('とりあえずマイリストから外しました');
}
});
} ,false);
return btn;
}
function createTagListButton() {
var btn = document.createElement('button');
btn.appendChild(document.createTextNode('tag'));
btn.className = 'tagGet';
btn.title = 'タグ取得';
btn.addEventListener('click', function(e) {
btn.disabled = true;
setButtonStyleUpdating(btn);
if (jQuery) {
var $btn = jQuery(btn), o = $btn.offset();
VideoTags.popupItems(_videoId, o.left, o.top + $btn.outerHeight());
} else {
VideoTags.popupItems(_videoId, e.pageX, e.pageY);
}
} ,false);
return btn;
}
function createNewTabLink() {
var a = document.createElement('a');
a.className = 'newTabLink';
a.target = '_blank';
a.title = 'この動画を新しいウィンドウで開く';
a.innerHTML = '▲';
return a;
}
var newTabLink = createNewTabLink();
if (w.WatchJsApi) {
nobr.appendChild(newTabLink);
}
var sel = createSelector();
var submit = creat###bmitButton(sel);
nobr.appendChild(sel);
nobr.appendChild(submit);
if (jQuery) {
jQuery(sel).keydown(function(e) {
e.stopPropagation();
if (e.keyCode === 13) { // ENTER
submit.click();
}
});
}
var tagBtn = createTagListButton();
nobr.appendChild(tagBtn);
var deleteDef = createDeleteDeflistItemButton();
nobr.appendChild(deleteDef);
nobr.appendChild(extArea);
body.watchId(_watchId, _videoId);
return body;
};
// XHRでクロスドメインを超えられない場合はこちら
// 将来マイリストのポップアップウィンドウが廃止されたら使えない
// (マイページから強引に生成するか?)
pt.getIframePanel = function(watchId) {
var _watchId = watchId;
var body = document.createElement('iframe');
body.name = 'nicomylistaddDummy';
body.className = 'mylistPopupPanel';
body.setAttribute('style', 'width: 130px; height: 24px; z-index: 10000; border: 1px solid silver; padding: 0; margin: 0; overflow: hidden');
body.watchId = function(w) {
if (w) {
_watchId = w;
body.contentWindow.location.replace("http:/" + "/www.nicovideo.jp/mylist_add/video/" + w);
return body;
}
return _watchId;
};
if (watchId !== '') {
body.src = "http:/" + "/www.nicovideo.jp/mylist_add/video/" + _watchId;
}
// ダミーメソッド
body.show = function() {
body.style.display = '';
};
body.hide = function() {
body.style.display = 'none';
};
return body;
};
return new Mylist();
})();
var MylistListPopup = function() { this.initialize.apply(this, arguments); };
MylistListPopup.prototype = {
initialize: function(mylistList, onItemClick) {
this._mylistList = mylistList.concat();
this.initializeView(mylistList);
this._onItemClick = onItemClick;
},
initializeView: function() {
var $ = jQuery;
this._$view = $([
'<div class="mylistListPopup popupMenu">',
'<div class="listInner">',
'<ul></ul>',
'</div>',
'</div>',
''].join(''));
this._$list = this._$view.find('ul');
this._$inner = this._$view.find('.listInner');
$('body').append(this._$view);
this.refresh();
this.initializeEvent(this._$view);
},
initializeEvent: function($view) {
$view.on('click', jQuery.proxy(function(e) {
if (e.button !== 0 || e.metaKey || e.shiftKey || e.altKey || e.ctrlKey) { return; }
var target = e.target, $target = jQuery(target);
this.hide();
e.preventDefault();
var mylistId = $target.attr('data-mylist-id');
var mylistName = $target.attr('data-mylist-name');
if (!mylistId) { return; }
var type = target.className;
if (typeof this._onItemClick === 'function') {
this._onItemClick(mylistId, mylistName, type);
}
}, this));
var self = this, closeTimer = null;
$view.hover(
function() {
if (closeTimer) { window.clearTimeout(closeTimer); }
},
function() {
closeTimer = window.setTimeout(function() { self.hide(); }, 1000);
});
$view = null;
},
adjustColumnCount: function() {
this._$inner.css({
'column-count': '',
'max-height': ''
});
var height = this._$view.outerHeight(),
clientHeight = jQuery(window).innerHeight(),
threshold = clientHeight * 0.4;
if (threshold < height) {
var columns = parseInt( height / threshold, 10) + 1;
this._$inner.css({
'column-count': columns,
'max-height': clientHeight * 0.8
});
}
},
updateList: function(mylistList) {
this._mylistList = mylistList.concat();
this.refresh();
},
refresh: function() {
var mylistList = this._mylistList;
this._$list.empty();
for (var i = 0, len = mylistList.length; i < len; i++) {
var mylist = mylistList[i];
this.appendItem(mylist.id, mylist.name, mylist.icon_id);
}
this.appendItem('default', 'とりあえずマイリスト');
this.adjustColumnCount();
},
appendItem: function(id, name, icon_id) {
var $mylist = jQuery([
'<li class="folder', icon_id, '">',
'<span class="icon"></span>',
'<a href="my/mylist/#/', id.replace('default', 'home'), '" class="name">',
name,
'</a>',
'</li>',
''].join(''));
$mylist.find('.icon, .name').attr({
'data-mylist-id': id,
'data-mylist-name': name
});
if (id === 'default') {
$mylist.addClass('deflist');
} else
if (id.indexOf('ext') === 0) {
$mylist.addClass('ext');
}
this._$list.append($mylist);
},
updateExist: function(watchId) {
if (!watchId) {
return;
}
this._$view.find('.exist').removeClass('exist');
this._$view.find('.name').each(function() {
var $this = jQuery(this), mylistId = $this.attr('data-mylist-id');
if (mylistId === 'default') { return; }
$this
.toggleClass('exist', window.WatchItLater.mylist.cache.hasItem(mylistId, watchId));
});
this._$view.find('.deflist .name')
.toggleClass('exist',   window.WatchItLater.mylist.findDeflistByWatchId(watchId) !== null);
},
show: function(elm, watchId) {
this.adjustColumnCount();
this._$view.addClass('show active');
if (!elm) { return; }
var
$ = jQuery,
$elm = $(elm),
o = $elm.offset(),
$view = this._$view,
$window = $(window),
scrollLeft = $window.scrollLeft(),
scrollTop  = $window.scrollTop();
$view.css({
top:  Math.max(o.top - $view.outerHeight(), 0, scrollTop),
left: o.left
});
if ($view.offset().left + $view.outerWidth() > $window.innerWidth() + scrollLeft) {
$view.css({
left: Math.max(0, $window.innerWidth() + scrollLeft - $view.outerWidth())
});
}
this.updateExist(watchId);
jQuery('body').on('click', $.proxy(this._onBodyClick, this));
},
hide: function() {
var $view = this._$view
.removeClass('show');
window.setTimeout(function() {
$view.css({top: '', left: '', right: ''}).removeClass('active');
}, 500);
jQuery('body').off('click', this._onBodyClick);
},
toggle: function(elm, watchId) {
if (this._$view.hasClass('avtive')) {
this.hide();
} else {
this.show(elm, watchId);
}
},
_onBodyClick: function() {
this.hide();
}
};
window.WatchItLater.mylist.cache = (function() {
var CacheList = function() { this.initialize.apply(this, arguments); };
CacheList.prototype = {
initialize: function() {
this.reset();
},
reset: function() {
this._cacheList = {};
},
setCache: function(mylistId, items) {
if (!this.hasCache(mylistId)) {
this._cacheList[mylistId] = new MylistCache();
}
this._cacheList[mylistId].update(items);
},
hasCache: function(mylistId) {
if (this._cacheList[mylistId]) {
return true;
}
return false;
},
hasItem: function(mylistId, watchId) {
if (!this.hasCache(mylistId)) {
return false;
}
return this._cacheList[mylistId].hasItem(watchId);
},
addItem: function(mylistId, watchId) {
if (!this.hasCache(mylistId)) {
return false;
}
this._cacheList[mylistId].addItem(watchId);
},
removeItem: function(mylistId, watchId) {
if (!this.hasCache(mylistId)) {
return false;
}
this._cacheList[mylistId].removeItem(watchId);
},
count: function(mylistId) {
if (!this.hasCache(mylistId)) {
return NaN;
}
this._cacheList[mylistId].count();
},
toJSON: function() {
var cacheList = this._cacheList;
return this._cacheList;
},
parse: function(jsonString) {
var data;
try {
data = JSON.parse(jsonString);
} catch (e) {
data = {};
}
this.reset();
for (var mylistId in data) {
var mylistCache = data[mylistId];
this._cacheList[mylistId] = new MylistCache(mylistCache);
}
}
};
var MylistCache = function() { this.initialize.apply(this, arguments); };
MylistCache.prototype = {
initialize: function(mylistData) {
this._name = '';
if (mylistData) {
this.update(mylistData);
}
},
update: function(mylistData) {
this._cache = [];
this._hash = {};
var items = mylistData.items ? mylistData.items : mylistData;
for (var i = 0, len = items.length; i < len; i++) {
var
item = items[i],
watchId = typeof item.getId === 'function' ? item.getId() : item.id;
this._cache.push({id: watchId});
this._hash[watchId] = true;
}
if (mylistData.name) {
this._name = mylistData.name;
}
},
hasItem: function(watchId) {
return this._hash[watchId] === true;
},
addItem: function(watchId) {
if (this.hasItem(watchId)) {
return;
}
this._hash[watchId] = true;
this._cache.push({id: watchId});
},
removeItem: function(watchId) {
if (!this.hasItem(watchId)) {
return;
}
delete this._hash[watchId];
this._cache = $.grep(this._cache, function(item) {
return item.id !== watchId;
});
},
count: function() {
return this._cache.length;
},
toJSON: function() {
return {
name:  this._name,
items: this._cache
};
},
parse: function(jsonString) {
var items;
try {
items = JSON.parse(jsonString);
} catch (e) {
items = [];
}
this.update(items);
}
};
var cacheList, noop = function() {};
var initialize = function() {
initialize = noop;
console.log('%cinitialize mylistCache', 'background: lightgreen;');
cacheList = new CacheList();
if (conf.enableLocalMylistCache) {
if (window.PlayerApp) {
$(window).on('beforeunload.watchItLater', function(e) {
window.localStorage.setItem('watchItLater_mylistCache', serialize());
});
}
var cacheData = window.localStorage.getItem('watchItLater_mylistCache');
if (cacheData) {
cacheList.parse(cacheData);
}
}
};
var hasCache = function(mylistId, watchId) {
initialize();
return cacheList.hasItem(mylistId, watchId);
};
var hasItem = function(mylistId, watchId) {
initialize();
return cacheList.hasItem(mylistId, watchId);
};
var addItem = function(mylistId, watchId) {
initialize();
cacheList.addItem(mylistId, watchId);
};
var removeItem = function(mylistId, watchId) {
initialize();
cacheList.removeItem(mylistId, watchId);
};
var setCache = function(mylistId, items) {
initialize();
cacheList.setCache(mylistId, items);
};
var serialize = function() {
initialize();
return JSON.stringify(cacheList);
};
var unserialize = function(json) {
initialize();
cacheList.parse(json);
};
var clearCache = function() {
window.localStorage.removeItem('watchItLater_mylistCache');
};
EventDispatcher.addEventListener('myMylistLoad', function(mylistId, list) {
setCache(mylistId, list || []);
});
EventDispatcher.addEventListener('onMylistItemAdded',  function(mylistId, watchId) {
initialize();
cacheList.addItem(mylistId, watchId);
});
EventDispatcher.addEventListener('onMylistItemDeleted',  function(mylistId, watchId) {
initialize();
cacheList.removeItem(mylistId, watchId);
});
return {
initialize: initialize,
hasItem: hasItem,
addItem: addItem,
setCache: setCache,
serialize: serialize,
unserialize: unserialize,
clearCache: clearCache
};
})();
var LocationHashParser = (function(conf, w) {
var self, dat = {};
function initialize() {
var hash = w.location.hash.toString();
var redirectedHash = window.sessionStorage.getItem('watchItLater_redirectedHash');
if (redirectedHash) {
console.log('%cNiconicodo redirect', 'background: lightgreen;');
hash = redirectedHash;
window.sessionStorage.removeItem('watchItLater_redirectedHash');
}
try {
if (hash.indexOf('#json={') === 0) {
dat = JSON.parse(hash.substr(6));
}
} catch (e) {
try {
dat = JSON.parse(decodeURIComponent(hash.substr(6)));
} catch(ex) {
console.log(ex);
}
console.log(e);
}
}
function setValue(key, value) {
dat[key] = value;
}
function getValue(key) {
return dat[key];
}
function deleteValue(key) {
delete dat[key];
}
function updateHash() {
var loc = window.location.href.split('#')[0];
location.replace(loc +  getHash());
}
function removeHash() {
if (location.hash.length <= 1) { return; }
var scrollTop = $(window).scrollTop();
var loc = window.location.href.split('#')[0];
location.replace(loc + '#');
$(window).scrollTop(scrollTop);
}
function getHash() {
var json = JSON.stringify(dat);
if (json === '{}') { return ''; }
return '#json=' + json;
}
function getUrl() {
var loc = window.location.href.split('#')[0];
return loc + getHash();
}
function clear() {
dat = {};
removeHash();
}
self = {
initialize: initialize,
setValue: setValue,
getValue: getValue,
deleteValue: deleteValue,
updateHash: updateHash,
removeHash: removeHash,
getHash: getHash,
getUrl: getUrl,
clear: clear
};
return self;
})(conf, w);
window.WatchItLater.loader.favMylists = (function() {
var lastUpdate = 0;
var favMylistList = [];
var host = location.host.replace(/^([\w\d]+)\./, 'www.');
var $ = w.$;
/**
*  お気に入りマイリストの取得。 jQueryのあるページでしか使えない
*  マイページを無理矢理パースしてるので突然使えなくなるかも
*/
var self = {
load: function(callback) {
if (!jQuery) return; //
function request(page) {
url = baseUrl + '?page=' + page;
httpRequest({
url: url,
onload: function(resp) {
var $r###lt = $(resp.responseText).find('#favMylist');
if ($r###lt.length >= 1) {
updateMaxPage($r###lt);
if (page === 1) { favMylistList = []; }
$r###lt.find('.outer').each(function() {
favMylistList.push(readBlock(this));
});
}
if (page < maxPage) {
setTimeout(function() {
page++;
request(page);
}, 500);
} else {
sort();
do_callback();
}
}
});
}
function readBlock(elm) {
var
$elm         = $(elm),
$a           = $elm.find('h5 a'), $desc = $elm.find('.mylistDescription'),
iconType     = $elm.find('.folderIcon').attr('class').split(' ')[1],
id           = ($a.attr('href').split('/').reverse())[0],
$postTime    = $elm.find('.postTime span'),
postTime     = $.trim($postTime.text()),
postTimeData = $postTime.data(),
$videoLink   = $elm.find('.videoTitle a'),
videoTitle   = $videoLink.text(),
videoHref    = $videoLink.attr('href'),
videoId      = videoHref ? (videoHref.split('/').reverse()[0]) : '';
return {
id: id,
name: $a.text(),
description: $desc.text(),
iconType: iconType,
lastVideo: {
title: videoTitle,
videoId: videoId,
postedAt: postTime,
postTimeData: postTimeData
}
};
}
function updateMaxPage($r###lt) {
var $paging = $r###lt.find('.pagerWrap:first .pager:first a');
maxPage = Math.min(Math.max($paging.length, 1), 3);
}
function sort() {
favMylistList.sort(function(a, b) {
return (a.lastVideo.postedAt < b.lastVideo.postedAt) ? 1 : -1;
});
}
function do_callback() {
if (typeof callback === 'function') { callback(favMylistList); }
}
var now = Date.now();
if (now - lastUpdate < 3 * 60 * 1000) {
do_callback();
return;
}
lastUpdate = now;
var
baseUrl = 'http://' + host + '/my/fav/mylist',
url = baseUrl,
maxPage = 1;
request(1);
}
};
return self;
})();
window.WatchItLater.loader.favTags = (function(w) {
var lastUpdate = 0;
var favTagList = [], favTagTextList = [];
var host = location.host.replace(/^([\w\d]+)\./, 'www.');
var $ = w.$;
var pt = function(){};
var load = function(callback) {
if (!jQuery) return; //
var now = Date.now();
if (now - lastUpdate < 60 * 1000) {
if (typeof callback === 'function') { callback(favTagList); }
return;
}
lastUpdate = now;
var api = 'http://' + host + '/api/favtag/list?t=' + now;
$.ajax({
url: api,
timeout: 30000,
complete: function(r###lt) {
if (r###lt.status !== 200) {
return;
}
try {
var json = JSON.parse(r###lt.responseText), items = json.favtag_items;
for (var i = 0, len = items.length; i < len; i++) {
var text = items[i]['tag'];
favTagList.push({href: '/tag/' + encodeURIComponent(text), name: items[i]['tag']});
favTagTextList.push(text);
}
EventDispatcher.dispatch('onFavTagsLoad', favTagTextList.concat());
if (typeof callback === 'function') { callback(favTagList); }
} catch (e) {
console.log('tag parse error!', e);
}
}
});
};
pt.load = load;
return pt;
})(w);
/**
*  左下に出るポップアップメッセージ
*
*/
var Popup = (function(){
function Popup() {}
Popup.show = function(text) {
console.log('%c' + text, 'background: cyan;');
if (w.WatchJsApi) {
text = text.replace(/[\n]/, '<br />');
require('watchapp/init/PopupMarqueeInitializer').popupMarqueeViewController.onData(
// Firefoxではflashの上に半透明要素を重ねられないのでとりあえず黒で塗りつぶす
'<span style="background: black;">' + text + '</span>'
);
}
};
Popup.alert = function(text) {
console.log('%c' + text, 'background: yellow;');
if (w.WatchJsApi) {
text = text.replace(/[\n]/, '<br />');
require('watchapp/init/PopupMarqueeInitializer').popupMarqueeViewController.onData(
'<span style="background: black; color: red;">' + text + '</span>'
);
} else {
w.alert(text);
}
};
Popup.hide = function() {
if (w.WatchJsApi) {
require('watchapp/init/PopupMarqueeInitializer').popupMarqueeViewController.stop();
}
};
return Popup;
})();
var KeyMatch = (function() {
var self;
function create(def) {
var ch = def.char[0].toUpperCase();
return {
prop: {
char: ch,
code: typeof def.code === 'number' ? def.code : ch.charCodeAt(0),
shift:  !!def.shift,
ctrl:   !!def.ctrl,
alt:    !!def.alt,
enable: !!def.enable
},
test: function(event) {
if (
this.prop.enable === true           &&
this.prop.shift   === event.shiftKey &&
this.prop.ctrl    === event.ctrlKey  &&
this.prop.alt     === event.altKey   &&
this.prop.code    === event.which
) {
event.preventDefault();
return true;
}
return false;
},
json: function() {
return JSON.stringify(this.prop);
}
};
}
self = {
create: create
};
return self;
})();
var TouchEventDispatcher = (function(target) {
var
self,
touchStartEvent = null,
touchEndEvent = null,
events = {
onflick: []
};
function dispatchEvent(name) {
var e = events[name];
for (var i =0, len = e.length; i < len; i++) {
e[i].apply(null, Array.prototype.slice.call(arguments, 1));
}
}
target.addEventListener('touchstart', function(e) {
touchStartEvent = e;
}, false);
target.addEventListener('touchcancel', function(e) {
touchStartEvent = null;
}, false);
target.addEventListener('touchend', function(e) {
touchEndEvent = e;
if (touchStartEvent !== null) {
var
sx = touchStartEvent.changedTouches[0].pageX, sy = touchStartEvent.changedTouches[0].pageY,
ex = touchEndEvent.changedTouches[0].pageX,   ey = touchEndEvent.changedTouches[0].pageY,
dx = (sx - ex), dy = (sy - ey), len = Math.sqrt(dx * dx + dy * dy), s;
if (len > 150) {
s = dy / len;
var a = Math.abs(s), ss = Math.round(s);
if (a <= 0.3 || a >= 0.7) {
var d;
if (ss < 0) { d = 'down'; } else if (ss > 0) { d = 'up'; }
else if (dx < 0) { d = 'right';} else { d = 'left'; }
dispatchEvent('onflick', {
direction: d,
distance: len,
x: dx, y: dy,
startEvent: touchStartEvent,
endEvent: touchEndEvent
});
}
}
}
touchStartEvent = touchEndEvent = null;
}, false);
function onflick(callback) {
events.onflick.push(callback);
}
self = {
onflick: onflick
};
return self;
})(w.document);
/**
*  リンクのマウスオーバーに仕込む処理
*  ここの表示は再考の余地あり
*/
var AnchorHoverPopup = (function(w, conf,EventDispatcher) {
var mylistPanel = Mylist.getPanel(''), hoverMenuDelay = conf.hoverMenuDelay * 1000;
mylistPanel.className += ' popup';
mylistPanel.style.display    = 'none';
document.body.appendChild(mylistPanel);
EventDispatcher.addEventListener('on.config.hoverMenuDelay', function(delay) {
delay = parseFloat(delay, 10);
if (isNaN(delay)) { return; }
hoverMenuDelay = Math.abs(delay * 1000);
});
function getBodyMarginLeft() {
try {
var cp = document.defaultView.getComputedStyle(document.body, null);
var ml = cp.getPropertyValue('margin-left');
if (ml.match(/^(\d+)px/)) {
return parseInt(RegExp.$1, 10);
}
return 0;
} catch (e) {
window.console.error('getBodyMarginLeft Exception!', e);
return 0;
}
}
function showPanel(watchId, baseX, baseY, w_touch) {
var cn = mylistPanel.className.toString();
if (w_touch === true) {
cn = cn.replace(' w_touch', '') + ' w_touch';
} else {
if (cn.indexOf('w_touch') >= 0 && mylistPanel.style.display !== 'none') {
// フリック操作で表示したパネルが出ている間はそちらを優先し、なにもしない
return;
}
cn = cn.replace(' w_touch', '');
}
VideoTags.hidePopup();
if (mylistPanel.className !== cn) mylistPanel.className = cn;
mylistPanel.style.display = '';
mylistPanel.watchId(watchId);
mylistPanel.style.right = null;
mylistPanel.style.left = (baseX) + 'px';
mylistPanel.style.top = Math.max(baseY - mylistPanel.offsetHeight, 0, document.body.scrollTop, document.documentElement.scrollTop) + 'px';
if (mylistPanel.offsetLeft + mylistPanel.offsetWidth > document.body.clientWidth + getBodyMarginLeft()) {
mylistPanel.style.left = null;
mylistPanel.style.right = 0;
}
}
var videoReg = /(\?cc_video_id=|\?cc_id=|watch\/)([a-z0-9]+)/;
var excludeReg = /(news|live|seiga)\..*?nicovideo\.jp/;
function each(w, watchId) {
this.w_eventInit = false;
this.addEventListener('mouseover', function() {
var mx = 0, my = 0, self = this;
if (typeof this.href === 'string' && !this.href.match(/playlist_type/)) {
this.setAttribute('href', this.href.split('?')[0]);
}
self.w_mouse_in = true;
self.w_mouse_timer = null;
self.w_mouse_timer = setTimeout(function() {
self.w_mouse_timer = null;
if (!self.w_mouse_in) {
return;
}
var o;
if (jQuery) {
var $e = jQuery(self);
var t = $e.text();
o = t !== "" ? $e.offset() : $e.find('*').offset();
var href = $e.closest('a').attr('href');
if (videoReg.test(href)) {
watchId = RegExp.$2;
}
showPanel(watchId, o.left, o.top);
} else
if (self.getBoundingClientRect) {
o = (self.firstChild && self.firstChild.tagName === 'IMG') ? self.firstChild.getBoundingClientRect() : self.getBoundingClientRect();
var top = Math.max(w.document.documentElement.scrollTop, w.document.body.scrollTop),
left = Math.max(w.document.documentElement.scrollLeft, w.document.body.scrollLeft);
showPanel(watchId, left + o.left, top + o.top);
} else {
showPanel(watchId, mx + 8, my + 8);
}
EventDispatcher.dispatch('mylistPanelOpen', mylistPanel, self, watchId);
}, hoverMenuDelay);
if (!this.w_eventInit) {
this.addEventListener('mouseout', function() {
self.w_mouse_in = false;
if (self.w_mouse_timer) {
clearTimeout(self.w_mouse_timer);
self.w_mouse_timer = null;
}
}, false);
if (!jQuery) {
this.addEventListener('mousemove', function(ev) {
mx = ev.pageX;
my = ev.pageY;
}, false);
}
this.w_eventInit = true;
}
}, false);
this.added = 1;
}
function bind(force, target) {
if (!conf.enableHoverPopup) { return; }
var a = Array.prototype.slice.apply(document.links), vreg = videoReg, ereg = excludeReg;
for (var i = 0, len = a.length; i < len; i++) {
var e = a[i];
var m, href= e.href;
if (
href &&
!e.added &&
(m = vreg.exec(href)) !== null &&
!ereg.test(href) &&
//            e.className !== "itemEcoLink" &&
e.className !== "playlistSaveLink"
) {
each.apply(e, [w, m[2]]);
}
}
}
function bindTouch() {
TouchEventDispatcher.onflick(function(e) {
var se = e.startEvent;
if (e.direction === 'right' && (se.target.tagName === 'A' || se.target.parentElement.tagName === 'A')) {
var
a = (se.target.tagName === 'A') ? e.startEvent.target : e.startEvent.target.parentElement,
href = a.href, vreg = videoReg, ereg = excludeReg, m, watchId;
if (
href &&
(m = vreg.exec(href)) !== null &&
!ereg.test(href) &&
//            e.className !== "itemEcoLink" &&
true
) {
watchId = m[2];
var o;
if (jQuery) {
var $a = jQuery(a);
var t = $a.text();
o = t !== "" ? $a.offset() : $a.find('*').offset();
showPanel(watchId, o.left, o.top, true);
} else {
o = (a.firstChild && a.firstChild.tagName === 'IMG') ? a.firstChild.getBoundingClientRect() : a.getBoundingClientRect();
var top  = Math.max(w.document.documentElement.scrollTop,  w.document.body.scrollTop),
left = Math.max(w.document.documentElement.scrollLeft, w.document.body.scrollLeft);
showPanel(watchId, left + o.left, top + o.top, true);
}
}
}
});
}
var lastUpdate = 0, linksCount = document.links.length,
bindLoop = function(nextTime) {
var now = Date.now();
var updateInterval = w.document.hasFocus() ? 3000 : 15000;
if (now - lastUpdate < updateInterval) {
var len = document.links.length;
if (linksCount === len) {
return;
}
linksCount = len;
}
bind();
lastUpdate = now;
};
var self = {
hidePopup: function() {
VideoTags.hidePopup();
mylistPanel.hide();
return this;
},
updateNow: function() {
bind();
lastUpdate -= 1500;
return this;
}
};
if (location.host === "ext.nicovideo.jp") {
bind();
} else {
var thumbnailReg = /\.smilevideo\.jp\/smile\?i=(\d+)/;
if (location.host === 'ch.nicovideo.jp' && jQuery) {
jQuery('.lazyimage, .thumb_video.thumb_114.wide img, .itemset li .image a .item').each(function() {
var $e = jQuery(this).text(' ');
var src = $e.attr('data-original') || $e.attr('src');
if (typeof src === 'string' && thumbnailReg.test(src)) {
each.apply(this, [w, 'so' + RegExp.$1]);
}
});
}
bindTouch();
bind();
setInterval(bindLoop, 500);
}
return self;
})(w, conf, EventDispatcher);
window.WatchItLater.popup = AnchorHoverPopup;
//===================================================
//===================================================
//===================================================
/**
*  マイリスト登録のポップアップウィンドウを乗っ取る処理
*
*  iframeの子ウィンドウ内に開かれた時に実行される
*  クロスドメインを越えられない環境ではこっちを使うしかない
*/
(function(){ // mylist window
if (w.location.href.indexOf('/mylist_add/') < 0 || w.name === 'nicomylistadd') return;
var $ = jQuery;
$('body,table,img,td').css({border:0, margin:0, padding:0, background: "transparent", overflow: 'hidden'});
$('#main_frm').css({background: '#fff', paddig: 0, borderRadius: 0}).addClass('mylistPopupPanel');
if ($('#edit_description').length < 1) {
$('#main_frm .font12:first').css({position: 'absolute', margin: 0, top: 0, left: 0, padding: 0, color: 'red', fontSize: '8pt'});
// ログインしてないぽい
return;
}
$('#box_success').css({position: 'absolute', top: 0, left: 0});
$('#box_success h1').css({color: 'black', fontSize: '8pt', padding: 0});
$('td').css({padding: 0});
// 「マイリストに登録しました」
//      $('.mb8p4:last').show();
//      $('.mb8p4:last h1').css({fontSize : "8pt"});
$('table:first').css({width: '200px'});
$('table:first td.main_frm_bg').css({height: '20px'});
$('table:first table:first').hide();
$('select')
.css({width: '64px',position: 'absolute', top:0, left:0, margin: 0})
.addClass('mylistSelect');
$('select')[0].selectedIndex = $('select')[0].options.length - 1;
$('#select_group option:last')[0].innerHTML = 'とりマイ';
//      var submit = document.createElement("input");
//      submit.className = 'mylistAdd';
//      submit.type  = "submit";
//      submit.value = "マ";
//      $(submit).css({position: 'absolute', top: 0, left: '64px'});
//      $('select')[0].parentNode.appendChild(submit);
$('#edit_description').hide();
w.document.documentElement.scrollTop  = 0;
w.document.documentElement.scrollLeft = 0;
$($.browser.safari ? 'body' : 'html').scrollTop(0);
w.window.close = function()
{
return;
};
w.window.alert = function()
{
w.document.write('<span style="position:absolute;top:0;left:0;font-size:8pt;color:red;">' +
arguments[0] + '</span>');
};
})();
//===================================================
//===================================================
//===================================================
window.WatchItLater.loader.videoArrayAPILoader = (function() {
var sessionId = 0;
var deferredList = {};
var cacheData = {};
var currentRequestIds = '', currentPromise;
var loaderFrame, loaderWindow;
var BASE_URL = 'http://i.nicovideo.jp/v3/video.array?v=';
var isChrome = window.navigator.userAgent.toLowerCase().indexOf('chrome') >= 0;
//WatchItLater.loader.videoArrayAPILoader.load('sm9').then(function(info) { console.log(info); });
var load = function(watchId) {
var ids = [], r###lt = {}, def = new $.Deferred(), timeoutTimer = null;
initialize();
$(typeof watchId !== 'string' ? watchId : [watchId]).each(function(i, id) {
if (cacheData[id]) {
r###lt[id] = cacheData[id];
} else {
ids.push(id);
}
});
ids = window._.uniq(ids);
if (ids.length < 1) {
window.setTimeout(function() { def.resolve(r###lt); }, 0);
return def;
}
var _ids = JSON.stringify(ids);
var onSuccess = function(infoList) {
$(ids).each(function(i, id) {
r###lt[id] = r###lt[id] || infoList[id] || cacheData[id];
});
window.clearTimeout(timeoutTimer);
currentRequestIds = ''; currentPromise = null;
def.resolve(r###lt);
def = null;
};
var onFail = function() {
window.clearTimeout(timeoutTimer);
console.log('%cVideoArrayAPILoader.onFail', 'color: red;');
currentRequestIds = ''; currentPromise = null;
if (def) {
def.reject();
}
def = null;
};
sessionId++;
timeoutTimer = window.setTimeout(onFail, 30 * 1000);
if (_ids === currentRequestIds) {
currentPromise.then(onSuccess, onFail);
return def;
}
currentRequestIds = _ids;
sendRequest(ids, sessionId).then(onSuccess, onFail);
return def.promise();
};
var sendRequest = function(ids, sessionId) {
var def = new $.Deferred();
currentPromise = def;
deferredList[sessionId] = def;
if (isChrome || true) {
// 基本的に i.nicovideo.jpのほうが高機能だが、Chrome + Tampermonkeyからは使えないため回避策
// ver 150703 iPhone用のAPIが使えなくなったのでFirefoxでもこっちを叩く
window.WatchItLater.loader.ceAPIClient.videoArray(ids, 'xml').then(
function(xml) { onXmlLoad(sessionId, xml); },
function()    { onXmlFail(sessionId); }
);
} else {
loaderWindow.location.replace(BASE_URL + ids.join(',') + '#' + sessionId);
}
return def.promise();
};
var parseVideoArray = function(xml) {
var $xml = $(xml), infoList = {};
$xml.find('video_info').each(function() {
var info = new parseVideoInfo($(this));
infoList[info.id] = cacheData[info.id] = cacheData[info.default_thread] = info;
if (info.threadIds && info.threadIds.length > 1) {
$(info.threadIds).each(function(i, threadId) {
infoList[threadId] = cacheData[threadId] = info;
});
}
});
return infoList;
};
var parseVideoInfo = function($xml) {
var info = {threadIds: []};
var elements = [
'id', 'user_id', 'title', 'description', 'length_in_seconds',
'thumbnail_url', 'first_retrieve', 'default_thread',
'view_counter', 'mylist_counter'];
$(elements).each(function(i, elm) {
info[elm] = $xml.find(elm + ':first').text();
});
info['num_res'] = $xml.find('thread:first num_res').text();
var duration = parseInt(info['length_in_seconds'], 10);
info['length'] = parseInt(duration / 60, 10) + ':' + (100 + (duration % 60)).toString().substr(1);
info['first_retrieve_t'] = info['first_retrieve'];
var DateFormat = require('watchapp/util/DateFormat');
info['first_retrieve'] = DateFormat.strftime('%Y-%m-%d %H:%M:%S', new Date(info['first_retrieve']));
$xml.find('thread id, channel_thread id').each(function() {
info.threadIds.push(this.innerHTML);
});
return info;
};
var onXmlLoad = function(sessionId, xml) {
if (deferredList[sessionId]) {
deferredList[sessionId].resolve(parseVideoArray(xml));
delete deferredList[sessionId];
currentPromise = null;
}
};
var onXmlFail = function(sessionId) {
if (deferredList[sessionId]) {
deferredList[sessionId].reject();
delete deferredList[sessionId];
currentPromise = null;
}
};
var initialize = function() {
initialize = window._.noop;
loaderFrame = document.createElement('iframe');
loaderFrame.name      = 'watchItLaterAPILoader';
loaderFrame.className = 'watchItLaterAPILoaderFrame xDomainLoaderFrame';
document.body.appendChild(loaderFrame);
loaderWindow = loaderFrame.contentWindow;
EventDispatcher.addEventListener('onMessage', function(data, type) {
if (type !== 'VideoArrayAPILoader') { return; }
var sessionId = data.session, xml = data.xml;
try {
//console.log('VideoArrayAPILoader.onMessage', data.session, data.xml);
onXmlLoad(sessionId, xml);
} catch (e) {
console.log('message parse error', e);
onXmlFail(sessionId);
}
});
};
// sample URL
// http://i.nicovideo.jp/v3/video.array?v=sm9,sm3393520,sm5909863,so23023492,1394173596
//initialize();
return {
load: load
};
})();
// 参考: http://www59.atwiki.jp/nicoapi/pages/24.html
// TampermonkeyはContent-Type: text/xmlのページで動かないため、
// 同じドメインにある適当なテキストapiを踏み台にして通信する
window.WatchItLater.loader.ceAPIClient = (function() {
var BASE_URL = 'http://api.ce.nicovideo.jp/api/v1/system.unixtime?';
var MESSAGE_ORIGIN = 'http://api.ce.nicovideo.jp/';
function CeAPIClient() {}
CeAPIClient.prototype = {
initialize: function() {
this.initialize = this.initialize_;
console.log('%cinitialize CeAPIClient', 'background: lightgreen;');
this._initialDef = new $.Deferred();
var sessions  = this._sessions  = {};
var cacheData = this._cacheData = {};
var loaderFrame = document.createElement('iframe');
loaderFrame.name      = 'ceAPILoader';
loaderFrame.className = 'ceAPILoaderFrame xDomainLoaderFrame';
document.body.appendChild(loaderFrame);
this._loaderWindow = loaderFrame.contentWindow;
EventDispatcher.addEventListener('onMessage', $.proxy(function(data, type) {
if (type !== 'ceAPILoader') { return; }
if (data.status === 'initialized') {
return this._onInitialized();
}
if (data.sessionId) {
var def = sessions[data.sessionId];
delete sessions[data.sessionId];
if (data.status === 'ok') {
cacheData[data.url] = data.body;
return def.resolve(data.body);
} else {
cacheData[data.url] = data.body;
window.setTimeout(function() { delete cacheData[data.url]; }, 60000);
return def.reject(data.status);
}
}
}, this));
this._loaderWindow.location.replace(BASE_URL);
return this._initialDef.promise();
},
initialize_: function() {
var def = new $.Deferred();
window.setTimeout(function() { def.resolve(); }, 0);
return def.promise();
},
_onInitialized: function() {
return this._initialDef.resolve();
},
_load: function(url) {
var def = new $.Deferred(), cacheData = this._cacheData;
if (cacheData[url]) {
window.setTimeout(function() { def.resolve(cacheData[url]); }, 0);
return def.promise();
}
var sessionId = 'session_' + Math.random();
this._sessions[sessionId] = def;
try {
this._loaderWindow.postMessage(JSON.stringify({
sessionId: sessionId,
url: url
}),
MESSAGE_ORIGIN);
} catch (e) {
console.log('%cException!', 'background: red;', e);
delete this._sessions[sessionId];
return def.reject();
}
return def.promise();
},
videoArray: function(watchId, format) {
return this.initialize().then($.proxy(function() {
var url = '/nicoapi/v1/video.array?v=';
var ids = [], def = new $.Deferred();
$(typeof watchId !== 'string' ? watchId : [watchId]).each(function(i, id) {
ids.push(id);
});
ids = window._.uniq(ids);
if (ids.length < 1) {
window.setTimeout(function() { def.resolve({}); }, 0);
return;
}
url = url + ids.join(',');
if (!format || format !== 'xml') {
url += '&__format=json';
}
this._load(url).then(function(r###lt) {
try {
if (!format && format !== 'xml') {
r###lt = JSON.parse(r###lt).nicovideo_video_response;
r###lt.status = r###lt['@status'];
delete r###lt['@status'];
}
} catch (e) {
console.log('%cJSON parse Error!', 'background: red;', e);
def.reject({});
}
return def.resolve(r###lt);
}, function() {
return def.reject();
});
return def.promise();
}, this));
}
};
return new CeAPIClient();
})();
//===================================================
//===================================================
//===================================================
var _watchController = function(w) {
var _false = function() { return false; };
var
watchInfoModel = require('watchapp/model/WatchInfoModel').getInstance() || {},
VideoExplorerInitializer = require('watchapp/init/VideoExplorerInitializer'),
PlayerInitializer = require('watchapp/init/PlayerInitializer'),
CommonModelInitializer = require('watchapp/init/CommonModelInitializer'),
WindowUtil = require('watchapp/util/WindowUtil'),
PlaylistInitializer = require('watchapp/init/PlaylistInitializer'),
nicoPlayer              = PlayerInitializer.nicoPlayerConnector || {},
videoExplorerController = VideoExplorerInitializer.videoExplorerController,
videoExplorer           = videoExplorerController.getVideoExplorer(),
videoExplorerContentType = require('watchapp/components/videoexplorer/model/ContentType'),
$ = w.$, WatchJsApi = w.WatchJsApi;
return {
isZeroWatch: function() {
return (window.WatchJsApi) ? true : false;
},
getWatchInfoModel: function() {
return watchInfoModel;
},
nicoSearch: function(word, search_type) {
if (!search_type) {
try {
var type = videoExplorerContentType.SEARCH;
search_type = videoExplorer.getContentList().getContent(type).getSearchType();
} catch(e) {
search_type = search_type || 'tag';
}
}
videoExplorerController.searchVideo(word, search_type);
AnchorHoverPopup.hidePopup();
},
showMylist: function(mylistId) {
videoExplorerController.showMylist(mylistId.toString());
},
clearDeflistCache: function() {
VideoExplorerInitializer.deflistVideoAPILoader._cache.clear();
},
clearMylistCache: function(id) {
if (id) {
VideoExplorerInitializer.mylistVideoAPILoader._cache.deleteElement(
'http://riapi.nicovideo.jp/api/watch/mylistvideo?id=' + id.toString()
);
} else {
VideoExplorerInitializer.mylistVideoAPILoader._cache.clear();
}
},
showDeflist: function() {
videoExplorerController.showDeflist();
},
changeScreenMode: function(mode) {
WatchJsApi.player.changePlayerScreenMode(mode);
setTimeout(function(){$(window).resize();}, 3000);
},
isFixedHeader: function() {
return !$('body').hasClass('nofix');
},
// ヘッダー追従かどうかを考慮したscrollTop
scrollTop: function(top, dur) {
var header = (this.isFixedHeader() ? $("#siteHeader").outerHeight() : 0);
if (top !== void 0) {
return $(window).scrollTop(top - header, dur);
} else {
return $(window).scrollTop() + header;
}
},
scrollToVideoPlayer: function(force) {
// 縦解像度がタグ+プレイヤーより大きいならタグの開始位置、そうでないならプレイヤーの位置にスクロール
// ただし、該当部分が画面内に#まっている場合は、勝手にスクロールするとかえってうざいのでなにもしない
var $body = $('body'), isContentFix = $body.hasClass('content-fix');
$body.addClass('w_noHover').removeClass('content-fix');
var h = $('#playerContainer').outerHeight() + $('#videoTagContainer').outerHeight();
var top = $(window).height() >= h ? '#videoTagContainer, #playerContainer' : '#playerContainer';
if (force) {
// 要素が画面内に#まっている場合でも、その要素の位置までスクロール
WindowUtil.scrollFit(top, 600);
} else {
// 要素が画面内に収まっている場合はスクロールしない
WindowUtil.scrollFitMinimum(top, 600);
}
$(window).scrollLeft(0);
$body.toggleClass('content-fix', isContentFix);
setTimeout(function() {
$body.removeClass('w_noHover');
}, 800);
},
play: function() {
nicoPlayer.playVideo();
},
pause: function() {
nicoPlayer.stopVideo();
},
togglePlay: function() {
var status = $("#external_nicoplayer")[0].ext_getStatus();
if (status === 'playing') {
this.pause();
} else {
this.play();
}
},
isPlaying: function() {
var status = $("#external_nicoplayer")[0].ext_getStatus();
return status === 'playing';
},
nextVideo: function() {
return nicoPlayer.playNextVideo();
},
prevVideo: function() {
return nicoPlayer.playPreviousVideo();
},
vpos: function(v) {
if (typeof v === 'number') {
return nicoPlayer.seekVideo(v);
} else {
return nicoPlayer.getVpos();
}
},
openSearch: function() {
VideoExplorerInitializer.expandButtonView.open();
},
closeSearch: function() {
videoExplorer.changeState(false);
videoExplorer.close();
},
openVideoOwnersVideo: function() {
if (this.isChannelVideo()) {
this.openChannelOwnersVideo();
} else {
this.openUpNushiVideo();
}
},
openUpNushiVideo: function() {
videoExplorerController.showOwnerVideo();
},
openChannelOwnersVideo: function() {
videoExplorerController.showMylist('-3');
},
openUserVideo: function(userId, userNick) {
videoExplorerController.showOtherUserVideos(userId, userNick);
},
openRecommend: function() {
var
type = videoExplorerContentType.RELATED_VIDEO,
open = function() {
var rel = VideoExplorerInitializer.videoExplorer._menu.getItemByContentType(type);
rel.select();
};
if (videoExplorer.isOpen()) {
open();
} else {
this.openSearch();
setTimeout(open, 500);
}
},
getVideoExplorerCurrentItems: function(format) {
var ac = videoExplorer._contentList.getActiveContent();
if (!ac || !ac.getItems) return [];
var items = ac.getItems();
if (!format) {
return items;
} else
if (format === 'playlist') {
var r###lt = [];
for (var i = items.length - 1; i >= 0; i--) {
r###lt.unshift(
videoExplorerController._item2playlistItem(items[i])
);
}
return r###lt;
}
},
getWatchId: function() {// スレッドIDだったりsmXXXXだったり
return watchInfoModel.v;
},
getVideoId: function() {// smXXXXXX, soXXXXX など
return watchInfoModel.id;
},
getMyNick: function() {
return CommonModelInitializer.viewerInfoModel.nickname;
},
getMyUserId: function() {
return CommonModelInitializer.viewerInfoModel.userId;
},
getPlaylistItems: function() {
return PlaylistInitializer.playlist.items || PlaylistInitializer.playlist.currentItems;
},
setPlaylistItems: function(items, currentItem) {
var playlist = PlaylistInitializer.playlist;
playlist.reset(
items,
'WatchItLater',
playlist.type,
playlist.option
);
if (currentItem) { playlist.playingItem = currentItem; }
else { playlist.playingItem = items[0]; }
},
shufflePlaylist: function(target) {
var x = this.getPlaylistItems(), items = [], i, currentIndex = -1, currentItem = null;
if (target === 'right') {
for (i = 0; i < x.length;) {
if (x[0]._isPlaying) {
currentIndex = i;
currentItem = x.shift();
items.push(currentItem);
break;
} else {
items.push(x.shift());
}
}
}
x = x.map(function(a){return {weight:Math.random(), value:a};})
.sort(function(a, b){return a.weight - b.weight;})
.map(function(a){return a.value;});
for (i = 0; i < x.length; i++) {
if (x[i]._isPlaying) {
items.unshift(x[i]);
} else {
items.push(x[i]);
}
}
var PlaylistManager = require('watchapp/view/playlist/PlaylistManager');
var pm = PlaylistManager, pv = PlaylistInitializer.playlistView;
var left = pm.getLeftSideIndex();
this.setPlaylistItems(items, currentItem);
pv.scroll(left);
},
clearPlaylist: function(target) {
var x = this.getPlaylistItems(), items = [], i, currentItem = null;
if (target === 'left') {
for (i = x.length - 1; i >= 0; i--) {
items.unshift(x[i]);
if (x[i]._isPlaying) {
currentItem = x[i];
break;
}
}
} else
if (target === 'right') {
for (i = 0; i < x.length ; i++) {
items.push(x[i]);
if (x[i]._isPlaying) {
currentItem = x[i];
break;
}
}
}
else {
for (i = 0; i < x.length; i++) {
if (x[i]._isPlaying) {
currentItem = x[i];
items.unshift(x[i]);
}
}
}
this.setPlaylistItems(items, currentItem);
},
appendSearchR###ltToPlaylist: function(mode) {
var
items = this.getPlaylistItems(),
searchItems = this.getVideoExplorerCurrentItems('playlist'),
uniq = {}, i, playingIndex = 0, c, len, currentItem = null;
if (!searchItems || searchItems.length < 1) {
return;
}
for (i = 0, len = items.length; i < len; i++) {
uniq[items[i].id] = true;
if (items[i]._isPlaying) { playingIndex = i; currentItem = items[i]; }
}
if (mode === 'next') {
for (i = searchItems.length - 1; i >= 0; i--) {
c = searchItems[i];
("undefined" === typeof c.type || "video" === c.type) && uniq[c.id] === void 0 && items.splice(playingIndex + 1, 0, c);
}
} else {
for (i = 0, len = searchItems.length; i < len; i++) {
c = searchItems[i];
("undefined" === typeof c.type || "video" === c.type) && uniq[c.id] === void 0 && items.push(c);
}
}
this.setPlaylistItems(items, currentItem);
},
insertVideoToPlaylist: function(id) {
WatchItLater.VideoInfoLoader.load(id).then(function(info) {
var PlaylistItem = require('watchapp/model/playlist/PlaylistItem');
var item = new PlaylistItem(info);
PlaylistInitializer.playlist.insertNextPlayingItem(item);
}, function(err) {
Popup.alert(err.message);
});
},
addDefMylist: function(description) {
var watchId = watchInfoModel.id;
setTimeout(function() {
Mylist.addDeflistItem(watchId, function(status, r###lt, replaced) {
Mylist.reloadDeflist();
if (status !== "ok") {
Popup.alert('とりあえずマイリストの登録に失敗: ' + r###lt.error.description);
} else {
var torimai = '<a href="/my/mylist">とりあえずマイリスト</a>';
Popup.show(
torimai +
(replaced ? 'の先頭に移動しました' : 'に登録しました')
);
}
}, description);
}, 0);
},
commentVisibility: function(v) {
if (v === 'toggle') {
return this.commentVisibility(!this.commentVisibility());
} else
if (typeof v === 'boolean') {
nicoPlayer.playerConfig.set({commentVisible: v});
return this;
} else {
var pc = nicoPlayer.playerConfig.get();
return pc.commentVisible;
}
},
deepenedComment: function(v) {
if (v === 'toggle') {
return this.deepenedComment(!this.deepenedComment());
} else
if (typeof v === 'boolean') {
nicoPlayer.playerConfig.set({deepenedComment: v});
return this;
} else {
var pc = nicoPlayer.playerConfig.get();
return pc.deepenedComment;
}
},
allowStageVideo: function(v) {
if (v === 'toggle') {
return this.allowStageVideo(!this.allowStageVideo());
} else
if (typeof v === 'boolean') {
nicoPlayer.playerConfig.set({allowStageVideo: v});
return this;
} else {
var pc = nicoPlayer.playerConfig.get();
return pc.allowStageVideo;
}
},
isStageVideoSupported: function() {
try {
var exp = w.document.getElementById('external_nicoplayer');
return exp.isStageVideoSupported();
} catch(e) {
console.log(e);
return false;
}
},
isStageVideoAvailable: function() {
try {
var exp = w.document.getElementById('external_nicoplayer');
return exp.isStageVideoAvailable();
} catch(e) {
console.log(e);
return false;
}
},
toggleStageVideo: function() {
if (!this.isStageVideoSupported()) {
Popup.alert('ハードウェアアクセラレーションを使用できない状態か、未対応の環境です');
return;
}
var isAllowed = this.allowStageVideo(), exp = $('#external_nicoplayer')[0];
exp.setIsForceUsingStageVideo(!isAllowed && conf.forceEnableStageVideo);
this.allowStageVideo(!isAllowed);
setTimeout($.proxy(function() {
isAllowed = this.allowStageVideo();
var isAvailable = this.isStageVideoAvailable();
Popup.show('ハードウェアアクセラレーション:' +
(isAllowed ? '設定ON' : '設定OFF') + ' / ' +
(isAvailable ? '使用可能' : '使用不能')
);
}, this), 100);
},
mute: function(v) {
var exp = w.document.getElementById('external_nicoplayer');
if (v === 'toggle') {
return this.mute(!this.mute());
} else
if (typeof v === 'boolean') {
exp.ext_setMute(v);
return this;
} else {
return exp.ext_isMute();
}
},
volume: function(v) {
var exp = w.document.getElementById('external_nicoplayer');
if (typeof v === 'string' && v.match(/^[+-]\d+$/)) {
this.volume(this.volume() + v * 1);
} else
if (typeof v === 'number' || (typeof v === 'string' && v.match(/^\d+$/))) {
exp.ext_setVolume(Math.max(0, Math.min(v * 1, 100)));
}
return exp.ext_getVolume();
},
isWide: function() {
var exp = w.document.getElementById('external_nicoplayer');
return exp.ext_isWide();
},
isPlaylistActive: function() {
return PlaylistInitializer.playlist.getPlaybackMode() !== 'normal';
},
isPlaylistRandom: function() {
return PlaylistInitializer.playlist.isShuffle();
},
isPlaylistContinuous: function() {
return PlaylistInitializer.playlist.getPlaybackMode() === 'continuous';
},
getOwnerIcon: function() {
try {
return this.isChannelVideo() ? watchInfoModel.channelInfo.iconUrl : watchInfoModel.uploaderInfo.iconUrl;
} catch (e) {
return 'http://uni.res.nimg.jp/img/user/thumb/blank_s.jpg';
}
},
getOwnerName: function() {
try {
return this.isChannelVideo() ? watchInfoModel.channelInfo.name    : watchInfoModel.uploaderInfo.nickname;
} catch (e) {
return '';
}
},
getOwnerId: function() {
try {
return this.isChannelVideo() ? watchInfoModel.channelInfo.id      : watchInfoModel.uploaderInfo.id;
} catch (e) {
return '0';
}
},
getOwnerType: function() {
try {
return this.isChannelVideo() ? 'channel' : 'user';
} catch (e) {
return 'channel';
}
},
getOwnerPage: function() {
try {
if (this.isChannelVideo()) {
return $('#ch_prof').find('.symbol').attr('href');
} else {
return '/user/' + this.getOwnerId();
}
} catch (e) {
return '';
}
},
isFavoriteOwner: function() {
try {
return this.isChannelVideo() ?
!!(watchInfoModel.channelInfo && watchInfoModel.channelInfo.isFavorited) :
watchInfoModel.uploaderInfo.isFavorited;
} catch (e) {
return false;
}
},
isVideoPublic: function() { // 投稿動画一覧を公開しているか? 公開マイリストがあるかどうかとは別なのでややこしい
return this.isChannelVideo() ? true : watchInfoModel.uploaderInfo.isUserVideoPublic;
},
isChannelVideo: function() {
return watchInfoModel.isChannelVideo();
},
getOwnerInfo: function() {
return {
type:       this.getOwnerType(),
name:       this.getOwnerName(),
icon:       this.getOwnerIcon(),
id:         this.getOwnerId(),
page:       this.getOwnerPage(),
isFavorite: this.isFavoriteOwner(),
isVideoPublic: this.isVideoPublic()
};
},
isSearchMode: function() {
return videoExplorer.isOpen(); ////return $('body').hasClass('videoExplorer');
},
isFullScreen: function() {
return $('body').hasClass('full_with_browser');
},
// フルスクリーンの時にタグとかプレイリストを表示する設定かどうか
isFullScreenContentAll: function() {
try {
var content = localStorage.BROWSER_FULL_OPTIONS;
if (typeof content !== 'string') return false;
var isAll = JSON.parse(content).content === 'all';
return isAll;
} catch(e) {
console.log('%cexception', 'background: red; color: white;', e);
return false;
}
},
isIchibaEmpty: function() {
return $('#ichibaMain')   .find('.ichiba_mainitem').length < 1;
},
postComment: function(comment, command) {
comment = $.trim(comment);
if (comment.length <= 0) { return; }
if (!command) { command = ''; }
setTimeout(function() {
try {
var exp = w.document.getElementById('external_nicoplayer');
console.log('postComment: ', [comment, command]);
if (!exp.externalPostChat(comment, command)) {
Popup.alert('コメント投稿に失敗しました');
}
} catch(e) {
Popup.alert('コメント投稿に失敗しました');
}
}, 0);
},
// スレッドIDから動画IDに変換。出来なかった時はそのまま返す
getTid2Vid: function(watchId, callback) {
if (!watchId.match(/^[0-9]+$/)) {
return callback(watchId);
}
window.WatchItLater.VideoInfoLoader.load(watchId).then(function(info) {
callback(info.id);
},
function() {
callback(watchId);
});
}
};
}; // end _watchController
(function() {
window.WatchItLater.WatchController =
window.WatchController = {
isZeroWatch:  function() { return window.WatchJsApi ? true : false; },
isFullScreen: function() { return false; },
isSearchMode: function() { return false; },
getTid2Vid: function(threadId, callback) { return callback(threadId); }
};
})();
var Util = (function() {
var Cache = {
storage: {},
get: function(key) {
if (!this.storage[key]) {
console.log('no cache');
return false;
} else
if (this.storage[key].cachedUntil <= Date.now()){
console.log('cache timeout');
delete this.storage[key];
return false;
} else {
console.log('cache exist');
return this.storage[key].data;
}
},
set: function(key, data, cacheTimeMs) {
cacheTimeMs = cacheTimeMs || 1000 * 60 * 10;
console.log('set cache', key, cacheTimeMs);
this.storage[key] = {
data: data,
cachedUntil: Date.now() + cacheTimeMs
};
return data;
}
};
var Browser = {
isWebkit: function() {
return navigator.userAgent.toLowerCase().indexOf('webkit') >= 0;
},
isFx: function() {
return navigator.userAgent.toLowerCase().indexOf('firefox') >= 0;
}
};
var
isMetaKey = function(e) {
if (e.button !== 0 || e.metaKey || e.shiftKey || e.altKey || e.ctrlKey) { return true; }
return false;
},
prevent = function(e) {
e.preventDefault(); e.stopPropagation();
},
scrollToVideoExplorer = function() {
if (!WatchController.isSearchMode()) { return; }
WindowUtil = require('watchapp/util/WindowUtil'),
window.setTimeout(function() {
WindowUtil.scrollFit($('#videoExplorer'));
}, 100);
};
var Closure = {
outScope: function(func) {
return new Function([
'(' + func.toString() + ').apply(this, arguments);'
].join(''));
},
openVideoOwnersVideo: function() {
return function(e) {
if (isMetaKey(e)) { return; }
prevent(e);
WatchController.openVideoOwnersVideo();
scrollToVideoExplorer();
};
},
openVideoOwnersNicorepo: function() {
return function(e) {
if (isMetaKey(e)) { return; }
if (conf.disableVideoExplorer && !WatchController.isSearchMode()) {
return;
}
prevent(e);
//WatchController.showMylist(NicorepoVideo.REPO_OWNER);
WatchController.showMylist('repo-owner-' + WatchController.getOwnerId());
scrollToVideoExplorer();
};
},
openDefMylist: function() {
return function(e) {
if (isMetaKey(e)) { return; }
prevent(e);
WatchController.showDeflist();
scrollToVideoExplorer();
};
},
openMylist: function(id) {
return function(e) {
if (isMetaKey(e)) { return; }
prevent(e);
WatchController.showMylist(id);
scrollToVideoExplorer();
};
},
openNicoSearch: function(word, type) {
return function(e) {
if (isMetaKey(e)) { return; }
if (WatchController.isZeroWatch()) {
prevent(e);
WatchController.nicoSearch(word, type);
scrollToVideoExplorer();
}
};
},
seekVideo: function(vpos) {
return function(e) {
if (isMetaKey(e)) { return; }
prevent(e);
WatchController.vpos(vpos);
};
},
showLargeThumbnail: function(url) {
return function() {
WatchController.showLargeThumbnail(url);
};
}
};
var Deferred = {
wait: function(msec) {
return function() {
var args = Array.prototype.slice.call(arguments, 0);
var d = new $.Deferred();
setTimeout(function() {
d.resolve.apply(d, args);
}, msec);
return d.promise();
};
}
};
var FullScreen = {
now: function() {
if (document.fullScreenElement || document.mozFullScreen || document.webkitIsFullScreen) {
return true;
}
return false;
},
request: function(target) {
var elm = typeof target === 'string' ? document.getElementById(target) : target;
if (!elm) { return; }
if (elm.requestFullScreen) {
elm.requestFullScreen();
} else if (elm.webkitRequestFullScreen) {
elm.webkitRequestFullScreen();
} else if (elm.mozRequestFullScreen) {
elm.mozRequestFullScreen();
}
},
cancel: function() {
if (!this.now()) { return; }
if (document.cancelFullScreen) {
document.cancelFullScreen();
} else if (document.webkitCancelFullScreen) {
document.webkitCancelFullScreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
}
}
};
var self = {
Cache: Cache,
Closure: Closure,
Deferred: Deferred,
Browser: Browser,
FullScreen: FullScreen,
here: function(func) { // えせヒアドキュメント
return func.toString().match(/[^]*\/\*([^]*)\*\/\}$/)[1].replace(/\{\*/g, '/*').replace(/\*\}/g, '*/');
}
};
return self;
})();
window.WatchItLater.util = Util;
// いったん凍結
//  var NicoNews = (function() {
//    var initialized = false;
//    var $button = null, $history = null, $ul = null, deteru = {}, $textMarquee, $textMarqueeInner;
//    var isHover = false;
//
//    function onNewsUpdate(news) {
//      var type = news.data.type, $current = null,
//          newsText = $textMarqueeInner.find('.categoryOuter:last').text() +
//                     $textMarqueeInner.find('.item .title, .item .header, .item .bannertext, .item .text').text(),
//          newsHref = $textMarqueeInner.find('a').attr('href');
//      if (deteru[newsHref]) {
//        $current = deteru[newsHref].remove();
//      } else {
//        $current = deteru[newsHref] = makeTopic(newsText, newsHref, type);
//      }
//      $ul.append($current);
//      $current.show(200, scrollToBottom);
//    }
//    function makeTopic(title, url, type) {
//      return $([
//        '<li style="display: none;">',
//        '<a href="', url , '" target="_blank" class="', type, ' title="', window.escape(title),'">', title, '</a>',
//        '</li>',
//      ''].join(''));
//    }
//    function scrollToBottom() {
//      if (!isHover) {
//        $history.animate({scrollTop: $('.newsHistory ul').innerHeight()}, 200);
//      }
//    }
//
//    var self = {
//      initialize: function(w) {
//        if (!w.WatchJsApi || initialized) { return; }
//        var TextMarqueeInitializer = require('watchapp/init/TextMarqueeInitializer');
//        $textMarquee = $('#textMarquee');
//        $textMarqueeInner = $textMarquee.find('.textMarqueeInner');
//
//        TextMarqueeInitializer.textMarqueeViewController.scheduler.addEventListener(
//          'schedule',
//          onNewsUpdate);
//
//        $button = $('<button class="openNewsHistory" title="ニコニコニュースの履歴を開く">▲</button>');
//        $history = $('<div class="newsHistory" style="display: none;"><ul></ul></div>');
//        $history.hover(
//          function() { isHover = true; },
//          function() { isHover = false; }
//        );
//        $ul = $history.find('ul');
//        $button.click(function() { self.toggle(); });
//
//        $textMarquee.append($button).append($history);
//        initialized = true;
//      },
//      open: function() {
//        var WindowUtil = require('watchapp/util/WindowUtil');
//        $history.show(200, function() {
//          scrollToBottom();
//          WindowUtil.scrollFitMinimum('.newsHistory', 200);
//        });
//      },
//      close: function() {
//        $history.hide(200);
//        isHover = false;
//      },
//      toggle: function() {
//        if ($history.is(':visible')) {
//          $button.text('▲');
//          this.close();
//        } else {
//          $button.text('▼');
//          this.open();
//        }
//      }
//    };
//    return self;
//  })();
/**
*  マイリストや検索API互換形式のデータを返すやつ
*/
var DummyMylist = function() { this.initialize.apply(this, arguments); };
DummyMylist.prototype = {
banner: '',
id: '-100',
sort: '4',
isDeflist: -1,
isWatchngCountFull: false,
isWatchngThisMylist: false,
itemCount: 0,
items: [],
rawData: {},
page: 1,
perPage: 32,
type: 2, // 2: MYLIST_VIDEO
//
// ver130726より新規追加 defineGetterのほうがいいかも
status: 'ok',
name: '',
description: '',
user_id: '',
user_nickname: 'ニコニコ動画',
default_sort: '1',
is_watching_this_mylist: false,
is_watching_count_full: false,
list: [],
// ここまで
initialize: function(param) {
this.rawData = {
status: 'ok',
list: [],
name: '総合ランキング',
description: '',
is_watching_count_full:  false,
is_watching_this_mylist: false,
user_nickname: '',
user_id: '',
sort: '1'
};
this._baseCreateTime = Date.now();//new Date();
this.rawData.user_nickname = param.user_nickname || WatchController.getMyNick();
this.rawData.user_id       = param.user_id       || WatchController.getMyUserId();
this.rawData.name          = param.name          || this.rawData.name;
this.rawData.description   = param.description   || '';
var ContentType = require('watchapp/components/videoexplorer/model/ContentType');
this.type = param.type || ContentType.MYLIST_VIDEO;
this.sort = this.rawData.sort = param.sort || this.sort;
this.id   = param.id || '-100';
this.status        = this.rawData.status;
this.list          = this.rawData.list;
this.name          = this.rawData.name;
this.description   = this.rawData.description;
this.default_sort  = this.rawData.sort || this.sort;
this.user_nickname = this.rawData.user_nickname || this.user_nickname;
this.user_id       = this.rawData.user_id;
},
setName: function(name) {
this.rawData.name = name;
},
getName: function() {
return this.rawData.name || '';
},
setPage: function(page) {
this.page = page;
this.items = this.rawData.list.slice(page * this.perPage - this.perPage, page * this.perPage);
},
push: function(item) {
if (!item.create_time) {
var tm = this._baseCreateTime - 60000 * this.itemCount;
item.create_time = tm;
}
this.rawData.list.push(item);
this.itemCount = this.rawData.list.length;
this.setPage(this.page);
},
unshift: function(item) {
if (!item.create_time) {
var tm = this._baseCreateTime + 60000 * this.itemCount;
item.create_time = tm;
}
this.rawData.list.unshift(item);
this.itemCount = this.rawData.list.length;
this.setPage(this.page);
},
slice: function(b, e) {
this.rawData.list = this.rawData.list.slice(b, e);
this.itemCount    = this.rawData.list.length;
this.setPage(this.page);
},
sortItem: function(sortId, force) {
sortId = parseInt(sortId, 10);
if (!!!force && (sortId < 0 || sortId === parseInt(this.sort, 10)) ) { return; }
var sortKey = ([
'create_time',        'create_time',
'mylist_comment',     'mylist_comment',
'title',              'title',
'first_retrieve',     'first_retrieve',
'view_counter',       'view_counter',
'thread_update_time', 'thread_update_time',
'num_res',            'num_res',
'mylist_counter',     'mylist_counter',
'length_seconds',     'length_seconds'
])[sortId],
order = (sortId % 2 === 0) ? 'asc' : 'desc';
if (!sortKey) { return; }
var compare= {
asc:   function(a, b) { return (a[sortKey]   > b[sortKey]  ) ? 1 : -1; },
desc:  function(a, b) { return (a[sortKey]   < b[sortKey]  ) ? 1 : -1; },
iasc:  function(a, b) { return (a[sortKey]*1 > b[sortKey]*1) ? 1 : -1; },
idesc: function(a, b) { return (a[sortKey]*1 < b[sortKey]*1) ? 1 : -1; },
// sortKeyが同一だった場合は動画IDでソートする(銀魂など、一部公式チャンネル動画向けの対応)
ascid: function(a, b) {
if (a[sortKey] !== b[sortKey]) {
return (a[sortKey]*1 > b[sortKey]*1) ? 1 : -1;
} else {
return a.id > b.id ? 1 : -1;
}
},
descid: function(a, b) {
if (a[sortKey] !== b[sortKey]) {
return (a[sortKey]*1 < b[sortKey]*1) ? 1 : -1;
} else {
return a.id < b.id ? 1 : -1;
}
},
};
// 偶数がascで奇数がdescかと思ったら特に統一されてなかった
if (
sortKey === 'first_retrieve'   ||
sortKey === 'thread_update_time'
) {
order = (sortId % 2 === 1) ? 'ascid' : 'descid';
} else
// 数値系は偶数がdesc
if (sortKey === 'view_counter'   ||
sortKey === 'num_res'        ||
sortKey === 'mylist_counter' ||
sortKey === 'length_seconds'
) {
order = (sortId % 2 === 1) ? 'iasc' : 'idesc';
}
this.sort = this.rawData.sort = sortId.toString();
this.rawData.list = window._.uniq(this.rawData.list.sort(compare[order]), 'id');
this.items = this.rawData.list.slice(0, 32);
this.list  = this.rawData.list.slice(0);
}
};
var DummyMylistVideo = function() { this.initialize.apply(this, arguments); };
DummyMylistVideo.prototype = {
id: 0,
title: '',
length: 0,
view_counter: 0,
num_res: 0,
mylist_counter: 0,
description_short: '',
first_retrieve: null,
thumbnail_url: null,
mylist_comment: '',
create_time: null,
type: 0, //'video',
_info: {},
initialize: function(info) {
this._info             = info._info || this;
this.id                = info.id;
this.length            = info.length;
this.mylist_counter    = info.mylist_counter || 0;
this.view_counter      = info.view_counter   || 0;
this.num_res           = info.num_res        || 0;
this.first_retrieve    = info.first_retrieve || '2000-01-01 00:00:00';
this.create_time       = info.create_time    || null;
this.thumbnail_url     = info.thumbnail_url  || 'http://res.nimg.jp/img/common/video_deleted_ja-jp.jpg' /* 「視聴できません」 */;
this.title             = info.title || '';
this.type              = info.type || 'video';
this.description_short = info.description_short;
this.length            = info.length         || '00:00';
this.length_seconds    = parseInt(info.length_seconds || 0, 10);
this.mylist_comment    = info.mylist_comment || '';
var ContentItemType = require('watchapp/components/videoexplorer/model/ContentItemType');
this.type              = info.type || ContentItemType.VIDEO;
if (this.length_seconds === 0 && this.length && this.length.indexOf(':') >= 0) {
var sp = this.length.split(':');
this.length_seconds = sp[0] * 60 + sp[1] * 1;
} else
if (this.length === '00:00' && this.length_seconds > 0) {
this.length = parseInt(this.length_seconds / 60, 10) + ':' + (this.length_seconds % 60);
}
if (typeof info.is_middle_thumbnail !== 'boolean') {
if (this.thumbnail_url.indexOf('.M') >= 0) {
this.thumbnail_url = this.thumbnail_url.replace(/\.M$/, '');
this.is_middle_thumbnail = true;
} else
if (this.thumbnail_url.indexOf('.M') < 0 &&
this.id.indexOf('sm') === 0) {
var threshold = 23608629, // .Mのついた最小ID?
_id = window._.parseInt(this.id.substr(2));
if (_id >= threshold) {
this.is_middle_thumbnail = true;
}
}
}
},
getType:        function() { return this.type; },
getInfo:        function() { return this; }, // 手抜き
getName:        function() { return this.title; },
getId:          function() { return this.id; },
getDescription: function() { return this.description_short; },
length_seconds: 0, // TODO:
thread_update_time: '2000-01-01 00:00:00' // TODO: 「コメントが新しい順でソート」に必要?
};
// 参考:
// http://looooooooop.blog35.fc2.com/blog-entry-1146.html
// http://toxy.hatenablog.jp/entry/2013/07/25/200645
// http://ch.nicovideo.jp/pita/blomaga/ar297860
// http://search.nicovideo.jp/docs/api/ma9.html
var NewNicoSearch = function() { this.initialize.apply(this, arguments); };
NewNicoSearch.API_BASE_URL  = 'http://api.search.nicovideo.jp/api/';
NewNicoSearch.PAGE_BASE_URL = 'http://search.nicovideo.jp/video/';
NewNicoSearch.prototype = {
_u: '',      // 24h, 1w, 1m, ft  期間指定
_ftfrom: '', // YYYY-MM-DD
_ftto: '',   // YYYY-MM-DD
_l: '',      // short long
_m: false,   // true=音楽ダウンロード
_sort: '',   // last_comment_time, last_comment_time_asc,
// view_counter,      view_counter_asc,
// comment_counter,   comment_counter_asc,
// mylist_counter,    mylist_counter_asc,
// upload_time,       upload_time_asc,
// length_seconds,    length_seconds_asc
_size: 32,   // 一ページの件数  maxは100
_issuer: 'watch-it-later',
_base_url: NewNicoSearch.API_BASE_URL,
initialize: function(params) {
},
load: function(params, callback) {
var url = this._base_url;
var data = {};
data.query   = params.query   || 'Qwatch';
data.service = params.service || ['video']; // video video_tag
data.search  = params.search  || ['title', 'tags', 'description'];
data.join    = params.join    || [
// TODO:投稿者IDを取得する方法がないか?
'cmsid', 'title', 'description', 'thumbnail_url', 'start_time',
'view_counter', 'comment_counter', 'mylist_counter', 'length_seconds', 'last_res_body'
//  'user_id', 'channel_id', 'main_community_id', 'ss_adlut'
];
data.filters = params.filters || [{}];
data.sort_by = params.sort_by || 'start_time';
data.order   = params.order   || 'desc';
data.timeout = params.timeout || 10000;
data.issuer  = params.issuer  || 'watch-it-later';
data.reason  = params.reason  || 'video-explorer'; // 'watchItLater';
data.size    = params.size    || 32;
data.from    = params.from    || 0;
if (params.sort_by === '_hot') { // 人気順ソートのパラメータ
data.hot_field = params.hot_field;
data.hot_from  = params.hot_from;
data.hot_to    = params.hot_to;
}
var cache_key = JSON.stringify({url: url, data: data}), cache = Util.Cache.get(cache_key);
if (cache) {
setTimeout(function() { callback(null, cache); }, 0);
return;
}
$.ajax({
url: url,
type: 'POST',
data: JSON.stringify(data),
timeout: 30000,
complete: function(r###lt) {
console.log('r###lt', r###lt);
if (r###lt.status !== 200) {
callback('fail', 'HTTP status:' + r###lt.status);
return;
}
var data;
try {
var lines = r###lt.responseText.split('\n'), head = JSON.parse(lines[0]);
if (head.values[0].total > 0) {
data = [head];
for (var i = 1, len = lines.length; i < len - 1; i++) {
data.push(JSON.parse(lines[i]));
}
} else {
data = [head, JSON.parse(lines[1]), {type: 'hits', values: []}, JSON.parse(lines[2])];
}
Util.Cache.set(cache_key, data);
} catch(e) {
console.log('Exception: ', e, r###lt);
callback('fail', 'JSON syntax');
return;
}
callback(null, data);
},
error: function(req, status, thrown) {
if (status === 'parsererror') {
return;
}
console.log('%c ajax error: ' + status, 'background: red', arguments);
callback('fail', status);
}
});
}
};
/**
*  niconico新検索の検索結果を既存の検索API互換形式に変換して返すやつ
*/
var NewNicoSearchWrapper = function() { this.initialize.apply(this, arguments); };
NewNicoSearchWrapper.prototype = {
_search: null,
sortTable: {f: 'start_time', v: 'view_counter', r: 'comment_counter', m: 'mylist_counter', l: 'length_seconds',
'_hot':     '_hot',    // 人気が高い順
'_explore': '_explore', // 新着優先
'_popular': '_popular', // 並び順指定なし
'_id': 'id'
},
initialize: function(params) {
this._search = params.search;
},
_buildSearchQuery: function(params) {
var query = {filters: []};
var sortTable = this.sortTable;
query.query   = params.searchWord;
query.search  = params.searchType === 'tag' ? ['tags'] : ['tags', 'title', 'description'];
query.sort_by = params.sort && sortTable[params.sort] ? sortTable[params.sort] : 'last_comment_time';
query.order   = params.order === 'd' ? 'desc' : 'asc';
query.size    = params.size || 32;
query.from    = params.page ? Math.max(parseInt(params.page, 10) - 1, 0) * query.size : 0;
var n = new Date();
var now = n.getTime();
switch (params.u) {
case '1h':
query.filters.push(this._buildStartTimeRangeFilter(new Date(now -   1 *  1 * 60  * 60 * 1000)));
break;
case '24h': case '1d':
query.filters.push(this._buildStartTimeRangeFilter(new Date(now -   1 * 24 * 60  * 60 * 1000)));
break;
case '1w':  case '7d':
query.filters.push(this._buildStartTimeRangeFilter(new Date(now -   7 * 24 * 60  * 60 * 1000)));
break;
case '1m':
query.filters.push(this._buildStartTimeRangeFilter(new Date(now -  30 * 24 * 60  * 60 * 1000)));
break;
case '3m':
query.filters.push(this._buildStartTimeRangeFilter(new Date(now -  90 * 24 * 60  * 60 * 1000)));
break;
case '6m':
query.filters.push(this._buildStartTimeRangeFilter(new Date(now - 180 * 24 * 60  * 60 * 1000)));
break;
default:
break;
}
if (query.sort_by === '_hot') {
// 人気が高い順ソート
(function() {
var DateFormat = require('watchapp/util/DateFormat');
var format = function(date) { return DateFormat.strftime('%Y-%m-%d %H:%M:%S', date); };
query.hot_field = 'mylist_counter';
query.hot_from = format(new Date(now - 1 * 24 * 60 * 60 * 1000));
query.hot_to   = format(n);
query.order = 'desc';
})();
}
if (query.sort_by === 'id') {
query.sort_by = 'start_time';
query.order = 'asc';
}
if (typeof params.userId === 'string' && params.userId.match(/^\d+$/)) {
query.filters.push({type: 'equal', field: 'user_id',    value: params.userId});
}
if (typeof params.channelId === 'string' && params.channelId.match(/^\d+$/)) {
query.filters.push({type: 'equal', field: 'channel_id', value: params.channelId});
}
if (typeof params.commentCount === 'string' && params.commentCount.match(/^[0-9]+$/)) {
query.filters.push({
type: 'range',
field: 'comment_counter',
include_lower: true,
from: params.commentCount
});
}
if (params.l === 'short') { // 5分以内
query.filters.push(this._buildLengthSecondsRangeFilter(0, 60 * 5));
} else
if (params.l === 'long' ) { // 20分以上
query.filters.push(this._buildLengthSecondsRangeFilter(60 * 20));
}
if (params.m === true) {    // 音楽ダウンロード
query.filters.push({type: 'equal', field: 'music_download', value: true});
}
// TODO: これの調査 → {field: 'ss_adult', type: 'equal', value: false}
return query;
},
_buildStartTimeRangeFilter: function(from, to) {
var DateFormat = require('watchapp/util/DateFormat');
var format = function(date) { return DateFormat.strftime('%Y-%m-%d %H:%M:%S', date); };
var range = {field: 'start_time',     type: 'range', include_lower: true, };
range.from = format(from);
if (to) range.to = format(to);
return range;
},
_buildLengthSecondsRangeFilter: function(from, to) {
var range = {field: 'length_seconds', type: 'range'};
if (to) { // xxx ~ xxx
range.from = Math.min(from, to);
range.to   = Math.max(from, to);
range.include_lower = range.include_upper = true;
} else { // xxx以上
range.from = from;
range.include_lower = true;
}
return range;
},
load: function(params, callback) {
var query = this._buildSearchQuery(params);
this._search.load(query, $.proxy(function(err, r###lt) {
this.onLoad(err, r###lt, params, query, callback);
}, this));
},
onLoad: function(err, r###lt, params, query, callback) {
if (err) {
console.log('load fail', err, r###lt);
callback('fail', {message: '通信に失敗しました1'});
return;
}
var searchR###lt;
searchR###lt = {
status: 'ok',
count: r###lt[0].values[0].total,
page: params.page,
list: []
};
var pushItems = function(items) {
var len = items.length;
for (var i = 0; i < len; i++) {
var item = items[i], description = item.description ? item.description.replace(/<.*?>/g, '') : '';
item.id = item.cmsid;
if (item.thumbnail_url.indexOf('.M') >= 0) {
item.thumbnail_url = item.thumbnail_url.replace(/\.M$/, '');
item.is_middle_thumbnail = true;
} else
if (item.thumbnail_url.indexOf('.M') < 0 &&
item.id.indexOf('sm') === 0) {
var threshold = 23608629, // .Mのついた最小ID?
_id = _.parseInt(item.id.substr(2));
if (_id >= threshold) {
item.is_middle_thumbnail = true;
}
}
searchR###lt.list.push({
id:                item.cmsid,
type:              0, // 0 = VIDEO,
length:            item.length_seconds ?
Math.floor(item.length_seconds / 60) + ':' + (item.length_seconds % 60 + 100).toString().substr(1) : '',
mylist_counter:    item.mylist_counter,
view_counter:      item.view_counter,
num_res:           item.comment_counter,
first_retrieve:    item.start_time,
create_time:       item.start_time,
thumbnail_url:     item.thumbnail_url,
title:             item.title,
description_short: description.substr(0, 150),
description_full:  description,
length_seconds:    item.length_seconds,
last_res_body:     item.last_res_body,
is_middle_thumbnail: item.is_middle_thumbnail
//            channel_id:        item.channel_id,
//            main_community_id: item.main_community_id
});
}
if (params.sort === '_id') {
searchR###lt.list = searchR###lt.list.sort(function(a, b){return a.id > b.id ? 1 : -1;});
}
// 投稿日時順ソートの時、投稿日時が同一だったら動画IDでソートする(公式銀魂のための対応)
if (params.sort === 'f') {
var aid = params.order === 'a' ? 1 : -1;
searchR###lt.list = searchR###lt.list.sort(function(a, b){
if (a.first_retrieve !== b.first_retrieve) {
return a.first_retrieve > b.first_retrieve ? aid : -aid;
}
return a.id > b.id ? aid : -aid;
});
}
};
for (var i = 1; i < r###lt.length; i++) {
if (r###lt[i].type === 'hits' && r###lt[i].endofstream) { break; }
if (r###lt[i].type === 'hits' && r###lt[i].values) {
pushItems(r###lt[i].values);
}
}
callback(null, searchR###lt);
}
};
// sug.search.nicovideo.jpはリアルタイムの入力補完用? で、関連タグはhttp://api.search.nicovideo.jp/api/tag/ っぽい
var NicoSearchSuggest = function() { this.initialize.apply(this, arguments); };
NicoSearchSuggest.API_BASE_URL = 'http://sug.search.nicovideo.jp/'; //'/suggestion/complete';
NicoSearchSuggest.prototype = {
_base_url: NicoSearchSuggest.API_BASE_URL,
initialize: function(params) {
},
load: function(word, callback) {
if (typeof word !== 'string' || word.length <= 0) {
throw new Error('wordが設定されてない!');
}
var url        = this._base_url + 'suggestion/complete/' + encodeURIComponent(word),
cache_key  = JSON.stringify({url: url, word: word}),
cache_time = 60 * 1000 * 1,
cache      = Util.Cache.get(cache_key);
if (cache) {
setTimeout(function() { callback(null, cache); }, 0);
return;
}
$.ajax({
url: url,
//        type: 'GET',
//        data: word,
timeout: 30000,
complete: function(r###lt) {
if (r###lt.status !== 200) {
callback('fail', 'HTTP status:' + r###lt.status);
return;
}
var data;
try {
data = JSON.parse(r###lt.responseText);
} catch(e) {
console.log('Exception: ', e, r###lt);
callback('fail', 'JSON syntax');
}
Util.Cache.set(cache_key, data, cache_time);
callback(null, data);
},
error: function(req, status, thrown) {
if (status === 'parsererror') {
return;
}
callback('fail', status);
}
});
}
};
var NicoSearchRelatedTag = function() { this.initialize.apply(this, arguments); };
NicoSearchRelatedTag.API_BASE_URL = 'http://api.search.nicovideo.jp/';
NicoSearchRelatedTag.prototype = {
_base_url: NicoSearchRelatedTag.API_BASE_URL,
initialize: function(params) {
},
load: function(word, callback) {
var url        = this._base_url + 'api/tag/',
cache_key  = JSON.stringify({url: url, word: word}),
cache_time = 60 * 1000 * 10,
cache      = Util.Cache.get(cache_key);
if (cache) {
setTimeout(function() { callback(null, cache); }, 0);
return;
}
var query = {query: word, service: ['tag_video'], from: 0, size: 100, timeout: 10000, reason: 'user'};
$.ajax({
url: url,
type: 'POST',
data: JSON.stringify(query),
timeout: 30000,
complete: function(r###lt) {
if (r###lt.status !== 200) {
callback('fail', 'HTTP status:' + r###lt.status);
return;
}
var data;
try {
var lines = r###lt.responseText.split('\n');
data = JSON.parse(lines[0]);
} catch(e) {
console.log('Exception: ', e, r###lt);
callback('fail', 'JSON syntax');
return;
}
Util.Cache.set(cache_key, data, cache_time);
callback(null, data);
},
error: function(req, status, thrown) {
if (status === 'parsererror') {
return;
}
callback('fail', status);
}
});
}
};
var VideoInfoLoader = function() { this.initialize.apply(this, arguments); };
VideoInfoLoader.BASE_URL = "http://riapi.nicovideo.jp/api/search/tag";
VideoInfoLoader.prototype = {
initialize: function(params) {
},
load: function(id, callback) {
var def = new $.Deferred();
var PlaylistInitializer = require('watchapp/init/PlaylistInitializer');
var cache_key = JSON.stringify({'VideoInfoLoaderCache': id}), cacheData = Util.Cache.get(cache_key);
if (cacheData) {
return def.resolve(cacheData);
}
if (id.toString().match(/^\d+$/)) { // watchId
PlaylistInitializer.videoInfoAPILoader.load(
[id],
function(err, resp) {
if (err !== null) {
return def.reject({message: '通信に失敗しました(1)', status: 'fail'});
}
if (resp.items && resp.items[id] && resp.items[id].id) {
if (typeof callback === 'function') { callback(null, resp.items[id]); }
return def.resolve(Util.Cache.set(cache_key, resp.items[id]));
}
err = {message: '動画が見つかりませんでした(1): ' + id, status: 'fail'};
if (typeof callback === 'function') { callback(err, null); }
return def.reject(err);
}
);
return def.promise();
}
// タグ検索APIの「もしかして: xxx」を使って動画情報を取得する
var HTTPUtil = require('watchapp/util/HTTPUtil');
HTTPUtil.loadXDomainAPI({ // videoId
url: VideoInfoLoader.BASE_URL,
type: 'GET',
dataType: 'json',
xhrFields: {
withCredentials: true
},
data: {
words: 'watch/' + id,
sort: 'f',
order: 'd',
page: '1',
mode: 'watch'
},
success: function(r###lt) {
if (r###lt.suggest_video && r###lt.suggest_video.id) {
if (typeof callback === 'function') { callback(null, r###lt.suggest_video); }
def.resolve(Util.Cache.set(cache_key, r###lt.suggest_video));
} else {
var err = {message: '動画が見つかりませんでした(2): ' + id, status: 'fail'};
if (typeof callback === 'function') { callback(err, null); }
def.reject(err);
}
},
error: function(resp) {
var err = {message: '通信に失敗しました(2)', status: 'fail'};
if (typeof callback === 'function') { callback(err, null); }
def.reject(err);
}
});
return def.promise();
}
};
window.WatchItLater.VideoInfoLoader = new VideoInfoLoader({});
var RelatedVideo = function() { this.initialize.apply(this, arguments); };
RelatedVideo.prototype = {
initialize: function(params) {
},
load: function(watchId) {
var def = new $.Deferred();
var VideoExplorerInitializer = require('watchapp/init/VideoExplorerInitializer');
VideoExplorerInitializer.relatedVideoAPILoader.load(
{'video_id': watchId},
function(err, r###lt) {
if (err !== null) {
return def.reject({message: '通信に失敗しました(1)', status: 'fail', err: err});
}
return def.resolve(r###lt);
}
);
return def.promise();
}
};
window.WatchItLater.RelatedVideo = new RelatedVideo({});
/**
*  動画視聴履歴をマイリストAPIと互換のある形式で返すことで、ダミーマイリストとして表示してしまう作戦
*/
var VideoWatchHistory = (function(w, Util){
function load(callback) {
var $, myNick, myId, url;
try{
$ = w.$; url = '/my/history';
myNick = window.WatchController.getMyNick(); myId = window.WatchController.getMyUserId();
} catch (e) {
console.log(e);
throw { message: 'エラーが発生しました', status: 'fail'};
}
var CACHE_KEY = 'videohistory', CACHE_TIME = 1000 * 60 * 1, cacheData = Util.Cache.get(CACHE_KEY);
if (cacheData) {
setTimeout(function() {callback(cacheData);}, 0);
return;
}
var r###lt = new DummyMylist({
id: '-1',
sort: '1',
name: myNick + 'の視聴履歴',
user_id: myId,
user_name: 'ニコニコ動画'
});
httpRequest({
url: url,
onload: function(resp) {
var $dom = $(resp.responseText), $list = $dom.find('#historyList');
$list.find('.outer').each(function() {
var
$item = $(this), $meta = $item.find('.metadata'), $title = $item.find('.section h5 a'),
id = $title.attr('href').split('/').reverse()[0], title = $title.text(),
duration = $item.find('.videoTime').text(),
viewCnt   = $meta.find('.play')   .text().split(':')[1].replace(/,/g, ''),
resCnt    = $meta.find('.comment').text().split(':')[1].replace(/,/g, ''),
mylistCnt = $meta.find('.mylist') .text().split(':')[1].replace(/,/g, ''),
postedAt  = '20' + $meta.find('.posttime').text().replace(/(年|月)/g, '-').replace(/(日| *投稿)/g, ''),
thumbnail = $item.find('.thumbContainer a .video').attr('src');
var item = new DummyMylistVideo({
id: id,
length: duration,
mylist_counter: mylistCnt,
view_counter: viewCnt,
num_res: resCnt,
first_retrieve: postedAt,
thumbnail_url: thumbnail,
title: title,
_info: {first_retrieve: postedAt},
description_short: $item.find('.section .posttime span').text()
});
r###lt.push(item);
});
callback(Util.Cache.set(CACHE_KEY, r###lt, CACHE_TIME));
},
onerror: function() {
Popup.alert('視聴履歴の取得に失敗しました');
}
});
}
var self = {
load : load
};
return self;
})(w, Util);
var VideoRecommendations = (function(w, Util){
var histories = {};
function request(callback) {
var $, url, myNick, myId;
try{
$ = w.$;
url = '/recommendations';
myNick = WatchController.getMyNick();
myId = WatchController.getMyUserId();
} catch (e) {
console.log(e);
throw { message: 'エラーが発生しました', status: 'fail'};
}
var CACHE_KEY = 'recommend', CACHE_TIME = 1000 * 60 * 1, cacheData = Util.Cache.get(CACHE_KEY);
if (cacheData) {
setTimeout(function() {callback(cacheData); }, 0);
return;
}
var r###lt = new DummyMylist({
id: '-2',
sort: '1',
name: 'あなたにオススメの動画'
});
httpRequest({
url: url,
onload: function(resp) {
var text = resp.responseText, lines = text.split(/[\r\n]/), found = false, data, i, len;
for (i = 0, len = lines.length; i < len; i++) {
var line = lines[i];
if (line.indexOf('var Nico_RecommendationsParams') >= 0 &&
lines[i + 5] && lines[i + 5].indexOf('first_data') >= 0) {
try {
data = JSON.parse(lines[i + 5].replace(/^.*?:/, ''));
} catch (e) {
console.log('JSON parse error!', i, lines[i + 5]);
break;
}
if (data && data.items) {
data.videos = data.items;
}
if (data && data.videos) {
found = true;
break;
}
}
}
if (!found) {
throw { message: '取得に失敗しました', status: 'fail'};
}
var df = require('watchapp/util/DateFormat');
for (i = 0, len = data.videos.length; i < len; i++) {
var video = data.videos[i];
if (video.item_type !== 'video') { break; }
if (typeof video.first_retrieve === 'number') {
video.first_retrieve =
df.strftime('%Y-%m-%d %H:%M:%S', new Date(video.first_retrieve * 1000));
}
var tag = video.recommend_tag;
if (!tag &&
video.additional_info &&
video.additional_info.sherlock &&
video.additional_info.sherlock.tag) {
tag = video.additional_info.sherlock.tag;
}
if (histories[video.id]) {
delete histories[video.id];
}
var item = new DummyMylistVideo({
id: video.id,
length: video.length,
mylist_counter: video.mylist_counter,
view_counter:   video.view_counter,
num_res:        video.num_res,
first_retrieve: video.first_retrieve,
thumbnail_url:  video.thumbnail_url,
title:          video.title_short,
_info: video,
description_short: '関連タグ: ' + tag
});
histories[video.id] = item;
}
for (var v in histories) {
r###lt.unshift(histories[v]);
}
r###lt.slice(0, 128);
callback(Util.Cache.set(CACHE_KEY, r###lt, CACHE_TIME));
},
onerror: function() {
throw { message: '取得に失敗しました', status: 'fail'};
}
});
}
function load(callback, param) {
request(function(r###lt) {
var viewPage = (param && typeof param.page === 'number') ? param.page : 1;
r###lt.setPage(viewPage);
callback(r###lt);
});
}
var self = {
load : load
};
return self;
})(w, Util);
var NicorepoVideo = (function(w, Util) {
if (!window.PlayerApp) return {};
var CACHE_TIME = 1000 * 60 * 10;
var getNicorepoTitle = function(type, param) {
var base = '【ニコレポ】';
if (type === 'all') {
return base + 'すべての動画';
} else
if (type === 'chcom') {
return base + 'お気に入りチャンネル&コミュニティの動画';
} else
if (type === 'mylist') {
return base + 'お気に入りマイリストの動画';
} else
if (type === 'owner') {
return WatchController.getOwnerName() + 'のニコレポ';
}
return base + 'お気に入りユーザーの動画';
};
var parseItemList = function($dom) {
var $list = $dom.find('.timeline');
return $list.find([
'.log-user-mylist-add',
'.log-user-uad-advertise',
'.log-user-video-upload',
'.log-user-video-review',
'.log-mylist-added-video',
'.log-community-video-upload',
'.log-user-video-round-number-of-view-counter',
'.log-user-video-round-number-of-mylist-counter'
].join(', '));
};
var ownerReg = /\/(community|user|channel)\/((co|ch)?\d+)\??/;
var parseNicorepoItem = function(src) {
var
DateFormat = require('watchapp/util/DateFormat'),
$item = $(src), $title = $item.find('.log-content .log-target-info a'),
id = $title.attr('href').split('/').reverse()[0].replace(/\?.*$/, ''), title = $title.text(),
duration = '--:--',
viewCnt   = '-',
resCnt    = '-',
mylistCnt = '-',
postedAt  = DateFormat.strftime('%Y-%m-%d %H:%M:%S', new Date($item.find('.log-footer-date time').attr('datetime'))),
thumbnail = $item.find('.log-target-thumbnail .video').attr('data-original'),
description_short = $.trim($item.find('.log-body').text()).replace(/(しました|されました)。/g, ''),
$owner = $item.find('.author-user, .author-community'),
ownerPage  = $owner.attr('href'),
ownerMatch = ownerReg.exec(ownerPage),
ownerName  = $owner.text(),
ownerId    = (ownerMatch !== null && ownerMatch.length >= 3) ? ownerMatch[2] : null,
ownerIcon  = $item.find('.log-author img').attr('data-original'),
mylistComment = $item.find('.log-content .log-subdetails').text().trim()
;
$item.removeClass('log').removeClass('passive').removeClass('first');
if (src.className === 'log-mylist-added-video') {
ownerName = $item.find('.log-body a:first').text();
ownerPage = $item.find('.log-body a:last').attr('href');
}
var item = new DummyMylistVideo({
id: id,
length: duration,
mylist_counter: mylistCnt,
view_counter: viewCnt,
num_res: resCnt,
first_retrieve: postedAt,
thumbnail_url: thumbnail,
mylist_comment: mylistComment,
title: title,
_info: {
first_retrieve: postedAt,
nicorepo_className: src.className,
nicorepo_log: [window._.escape(description_short)],
nicorepo_owner: {
id: ownerId,
icon: ownerIcon,
page: ownerPage,
name: ownerName
}
},
description_short: description_short
});
return item;
};
var loadPage = function(baseUrl, r###lt, nextLink, type) {
var def = new $.Deferred();
if (nextLink === null) {
return def.resolve(baseUrl, r###lt, null, null);
}
var url = baseUrl;
if (type === 'offset') {
url += nextLink ? ('&offset='        + nextLink) : '';
} else {
url += nextLink ? ('&last_timeline=' + nextLink) : '';
}
console.log('load Url=', url);
$.ajax({
url: url,
timeout: 30000
}).then(
function(resp) {
var $dom = $(resp),
$nextPageLink = $dom.find('.next-page-link'),
hasNextPage = $nextPageLink.length > 0;
parseItemList($dom).each(function() {
r###lt.push(parseNicorepoItem(this));
});
var nextLinkReg = /(last_timeline|offset)=(\d+)/;
if (hasNextPage) {
var href = $nextPageLink.attr('href');
if (nextLinkReg.test(href)) {
def.resolve(baseUrl, r###lt, RegExp.$2, RegExp.$1);
} else {
def.resolve(baseUrl, r###lt, null, null);
}
} else {
def.resolve(baseUrl, r###lt, null, null);
}
},
function() {
def.reject();
});
return def.promise();
};
var pipeRequest = function(baseUrl, r###lt, maxPages, callback) {
var def = new $.Deferred(), p = def.promise();
for (var i = maxPages; i >= 0; i--) {
p = p.then(loadPage);
if (i > 0) p = p.then(Util.Deferred.wait(300));
}
p.then(
function() {
var uniq = {}, uniq_items = [];
for (var i = r###lt.rawData.list.length - 1; i >= 0; i--) {
var item = r###lt.rawData.list[i], id = item.id, mc = item.mylist_comment;
if (uniq[id + mc]) {
uniq[id + mc]._info.nicorepo_log.push(item.first_retrieve + ' ' + item._info.nicorepo_log[0].replace(/^.*?さん(の|が)動画(が|を) ?/, ''));
} else {
uniq[id + mc] = item;
}
}
for (var v in uniq) {
uniq_items.unshift(uniq[v]);
}
r###lt.rawData.list = uniq_items;
callback(r###lt);
}
);
def.resolve(baseUrl, r###lt, '', '');
};
var request = function(param) {
var url, nickname, userId, type, baseUrl;
var def = new $.Deferred();
try {
url      = '';
nickname = param.nickname || window.WatchController.getMyNick();
userId   = param.userId   || window.WatchController.getMyUserId();
type     = param.type     || 'user';
baseUrl  = '/my/top/' + type + '?innerPage=1&mode=next_page';
if (param.userId) {
baseUrl = '/user/'+ param.userId +'/top?innerPage=1&mode=next_page';
}
} catch (e) {
console.log(e);
return def.reject({message: 'エラーが発生しました', status: 'fail'});
}
var cacheData = Util.Cache.get(baseUrl);
if (cacheData) {
return def.resolve(cacheData);
}
var
r###lt = new DummyMylist({
id: '-10',
sort: '1',
default_sort: '1',
name: getNicorepoTitle(type, param),
user_id:       type === 'owner' ? WatchController.getOwnerId()   : userId,
user_nickname: type === 'owner' ? WatchController.getOwnerName() : nickname
});
pipeRequest(baseUrl, r###lt, 2, function(r###lt) {
def.resolve(Util.Cache.set(baseUrl, r###lt, CACHE_TIME));
});
return def.promise();
};
var load = function(callback, param) {
return request(param)
.then(function(r###lt) {
var viewPage = (param && typeof param.page === 'number') ? param.page : 1;
r###lt.sortItem(param.sort || 1, true);
r###lt.setPage(viewPage);
if (typeof r###lt === 'function') { callback(r###lt); }
return this.done(r###lt);
}, function() {
return this.fail({message: 'ニコレポの取得に失敗しました', status: 'fail'});
});
};
var self = {
load: load,
REPO_ALL:    -10,
REPO_USER:   -11,
REPO_CHCOM:  -12,
REPO_MYLIST: -13,
REPO_OWNER:  -14,
loadAll:    function(callback, p) {
p = p || {};
p.type = 'all';
return self.load(callback, p);
},
loadUser:   function(callback, p) {
p = p || {};
p.type = 'user';
return self.load(callback, p);
},
loadChCom:  function(callback, p) {
p = p || {};
p.type = 'chcom';
return self.load(callback, p);
},
loadMylist: function(callback, p) {
p = p || {};
p.type = 'mylist';
return self.load(callback, p);
},
loadOwner: function(callback, p) {
p = p || {};
p.type = 'owner';
p.userId = window.WatchController.getOwnerId();
return self.load(callback, p);
}
};
window.WatchItLater.NicorepoVideo = self;
return self;
})(w, Util);
/**
*  ランキングのRSSをマイリストAPIと互換のある形式に変換することで、ダミーマイリストとして表示してしまう作戦
*/
var VideoRanking = (function(w, Util) {
if (!window.PlayerApp) return {};
var $ = jQuery;
var
genreIdTable = {
all:        -100,
g_ent2:     -110,
ent:        -111,
music:      -112,
sing:       -113,
play:       -114,
dance:      -115,
vocaloid:   -116,
nicoindies: -117,
g_life2:    -120,
animal:     -121,
cooking:    -122,
nature:     -123,
travel:     -124,
sport:      -125,
lecture:    -126,
drive:      -127,
history:    -128,
g_politics: -130,
g_tech:     -140,
science:    -141,
tech:       -142,
handcraft:  -143,
make:       -144,
g_culture2: -150,
anime:      -151,
game:       -152,
toho:       -153,
imas:       -154,
radio:      -155,
draw:       -156,
g_other:    -160,
are:        -161,
diary:      -162,
other:      -163
//        r18:        -170
},
genreNameTable = {
all:        'カテゴリ合算',
g_ent2:     'エンタメ・音楽',
ent:        'エンターテイメント',
music:      '音楽',
sing:       '歌ってみた',
play:       '演奏してみた',
dance:      '踊ってみた',
vocaloid:   'VOCALOID',
nicoindies: 'ニコニコインディーズ',
g_life2:    '生活・一般・スポ',
animal:     '動物',
cooking:    '料理',
nature:     '自然',
travel:     '旅行',
sport:      'スポーツ',
lecture:    'ニコニコ動画講座',
drive:      '車載動画',
history:    '歴史',
g_politics: '#治',
g_tech:     '科学・技術',
science:    '科学',
tech:       'ニコニコ技術部',
handcraft:  'ニコニコ手芸部',
make:       '作ってみた',
g_culture2: 'アニメ・ゲーム・絵',
anime:      'アニメ',
game:       'ゲーム',
toho:       '東方',
imas:       'アイドルマスター',
radio:      'ラジオ',
draw:       '描いてみた',
g_other:    'その他',
are:        '例のアレ',
diary:      '日記',
other:      'その他',
r18:        'R-18'
},
termIdTable = {
'hourly':      0,
'daily':   -1000,
'weekly':  -2000,
'monthly': -3000,
'total':   -4000
},
termNameTable = {
'hourly':      '(毎時)',
'daily':       '(24時間)',
'weekly':      '(週間)',
'monthly':     '(月間)',
'total':       '(合計)'
},
idTermTable = {},
idGenreTable = {}
;
if (conf.debugMode) { genreIdTable['r18'] = -170; }
for (var genre in genreIdTable) { idGenreTable[genreIdTable[genre]] = genre;}
for (var term  in termIdTable ) { idTermTable [termIdTable [term ]] = term; }
/**
*  ニコニコ動画ランキングのRSSをマイリストAPI互換のデータ形式に変換
*/
var rss2mylist = function(xml) {
var
$x = $(xml),
title = $x.find('channel title:first').text(),
$items = $x.find('channel item'),
r###lt = new DummyMylist({
name: title,
id: '-100'
});
$items.each(function() {
var video = parseRssItem($(this));
var item = new DummyMylistVideo({
id: video.id,
length: video.duration,
mylist_counter: video.mylistCnt,
view_counter: video.viewCnt,
num_res: video.resCnt,
first_retrieve: video.postedAt,
thumbnail_url: video.thumbnail,
title: video.title.replace(/^.*?第(\d+)位/, '第000$1位').replace(/^第\d+(\d{3})位/, '第$1位'),
_info: {first_retrieve: video.postedAt},
description_short: video.description.substring(0, 50)
});
r###lt.push(item);
});
return r###lt;
};
var parseRssItem = function($item) {
var
desc_cdata = $item.find('description').text(),
$desc      = $('<div>' + desc_cdata + '</div>');
return {
title       : $item.find('title')                  .text(),
id          : $item.find('guid')                   .text().split('/').reverse()[0],
duration    : $desc.find('.nico-info-length')      .text(),
viewCnt     : $desc.find('.nico-info-total-view')  .text().replace(/,/g, ''),
resCnt      : $desc.find('.nico-info-total-res')   .text().replace(/,/g, ''),
mylistCnt   : $desc.find('.nico-info-total-mylist').text().replace(/,/g, ''),
postedAt    : $desc.find('.nico-info-date')        .text()
.replace(/(年|月)/g, '-')
.replace(/:/g, ':')
.replace(/(日)/g, ''),
description : $desc.find('.nico-description')      .text(),
thumbnail   : $desc.find('.nico-thumbnail img').attr('src')
};
};
var pipeRequest = function(baseUrl, r###lt, page, maxPage) {
var def = new $.Deferred(), p = def.promise();
var getPipe = function(r###lt, url, page) {
return function() {
console.log('load RSS', url, page);
return $.ajax({
url: url,
timeout: 30000,
data: {rss: '2.0', lang: 'ja-jp', page: page},
beforeSend: function(xhr) {
xhr.setRequestHeader('X-Requested-With', {toString: function(){ return ''; }});
}
}).then(function(resp) {
var res = rss2mylist(resp);
for (var i = 0, len = res.rawData.list.length; i < len; i++) {
r###lt.push(res.rawData.list[i]);
}
});
};
};
for (var i = page; i <= maxPage; i++) {
p = p.then(getPipe(r###lt, baseUrl, i));
if (i < maxPage) { p = p.then(Util.Deferred.wait(300)); }
}
def.resolve();
return p;
};
var CACHE_TIME = 1000 * 60 * 30;
var request = function(baseUrl, page, maxPage) {
var def = new $.Deferred();
var cacheData = Util.Cache.get(baseUrl);
if (cacheData) {
return def.resolve(cacheData);
}
var r###lt = new DummyMylist({
name: '総合ランキング',
id: '-100'
});
pipeRequest(baseUrl, r###lt, page, maxPage).then(
function() {
def.resolve(Util.Cache.set(baseUrl, r###lt, CACHE_TIME));
},
function() {
def.reject();
});
return def.promise();
};
var parseParam = function(param) {
var
id = parseInt(param.id || -100, 10),
genreId  = getGenreId(id),
termId   = getTermId(id),
category = idGenreTable[genreId] || 'all', type = 'fav', term = 'daily', lang= 'ja-jp',
viewPage = (param && typeof param.page === 'number') ? param.page : 1,
genreName = genreNameTable[category] || genreNameTable['all'],
maxRssPage = 1, sort = param.sort || '4';
term = idTermTable[termId] || idTermTable[0];
maxRssPage = (category === 'all' && term !== 'hourly') ? 3 : 1;
return {
genreId: genreId,
genreName: genreName,
category: category,
type: type,
term: term,
lang: lang,
viewPage: viewPage,
sort: sort,
maxRssPage: maxRssPage,
baseUrl:
'/ranking/'+ type +'/'+ term + '/'+ category //+'?rss=2.0&lang=' + lang
};
};
var loadRanking = function(param) {
var p = parseParam(param);
return request(p.baseUrl, 1, p.maxRssPage)
.then(function(r###lt) {
r###lt.name = p.genreName;
r###lt.setPage(p.viewPage);
this.done(r###lt);
});
};
var load = function(onload, param) {
var p = parseParam(param);
return request(p.baseUrl, 1, p.maxRssPage)
.then(function(r###lt) {
r###lt.name = p.genreName;
r###lt.setPage(p.viewPage);
if (typeof onload === 'function') {
onload(r###lt);
}
return this.done(r###lt);
}, function() {
return this.fail({message: 'ランキングの取得に失敗しました', status: 'fail'});
});
};
var getTermId = function(t) {
if (typeof t === 'string') {
return termIdTable[t] || 0;
} else
if (typeof t === 'number'){
return (t - (t % 1000)) % 10000;
}
return 0;
};
var getGenreId = function(g, term) {
if (typeof g === 'string') {
return (genreIdTable[g] || 0) + getTermId(term);
} else
if (typeof g === 'number'){
return g % 1000;
} else {
return genreIdTable;
}
};
var getGenreName = function(g) {
if (typeof g === 'number' || (typeof g === 'string' && g.match(/^-?[0-9]+$/))) {
g = g % 1000;
var genre = idGenreTable[g];
return genreNameTable[genre];
} else
if (typeof g === 'string') {
return genreNameTable[g];
} else {
return genreNameTable;
}
};
var getCategory = function(g) {
if (typeof g === 'number') {
g = g % 1000;
return idGenreTable[g - (g %10)];
} else
if (typeof g === 'string') {
g  = genreIdTable[g];
return idGenreTable[g - (g %10)];
} else {
return 'all';
}
};
var self = {
load: load,
getTermId: getTermId,
getGenreId: getGenreId,
getGenreName: getGenreName,
getCategory: getCategory
};
WatchItLater.VideoRanking = self;
return self;
})(w, Util);
/**
*  チャンネル動画一覧をマイリストAPIと互換のある形式で返すことで、ダミーマイリストとして表示してしまう作戦
*/
var ChannelVideoList = (function(w, Util){
if (!window.PlayerApp) return {};
var
CACHE_TIME = 1000 * 60 * 10, MAX_PAGE = 3,
getPipe = function(baseUrl, r###lt, page) {
return function(hasPage) {
var def = new $.Deferred();
if (!hasPage) return def.resolve(hasPage);
var url = baseUrl + '?page=' + page;
console.log('load page', url);
$.ajax({url: url, timeout: 30000}).then(function(resp) {
var hasNextPage = parseItems(resp, r###lt);
def.resolve(hasNextPage);
}, function(err) {
def.reject(err);
});
return def.promise();
};
},
pipeRequest = function(baseUrl, r###lt) {
var def = new $.Deferred(), p = def.promise();
var maxPage = MAX_PAGE;
for (var i = 1; i <= maxPage; i++) {
p = p.then(getPipe(baseUrl, r###lt, i));
if (i < maxPage) { p = p.then(Util.Deferred.wait(300)); }
}
p.then(function() {
this.done(r###lt);
});
def.resolve(true);
return p;
},
load = function(callback, params) {
var myId, url, id, ownerName, def = new $.Deferred();
try{
id = params.id.toString().replace(/^ch/, '');
ownerName = params.ownerName;
url = 'http://ch.nicovideo.jp/channel/ch'+ id + '/video';
myId = window.WatchController.getMyUserId();
} catch (e) {
console.log(e);
throw { message: 'エラーが発生しました', status: 'fail'};
}
var CACHE_KEY = 'ch-' + id, cacheData = Util.Cache.get(CACHE_KEY);
if (cacheData) {
if (typeof callback === 'function') {
setTimeout(function() { callback(cacheData); } , 0);
}
setTimeout(function() { def.resolve(cacheData); } , 0);
return def.promise();
}
var r###lt = new DummyMylist({
id: 'ch' + id,
sort: '6',
name: ownerName + 'の動画',
user_id: myId,
user_name: 'ニコニコ動画'
});
pipeRequest(url, r###lt).then(function() {
Util.Cache.set(CACHE_KEY, r###lt, CACHE_TIME);
if (typeof callback === 'function') callback(r###lt);
def.resolve(r###lt);
});
return def.promise();
},
parseItems = function(html, r###lt) {
var $html = $(html), $list = $html.find('.contents_list .item');
var hasNextPage = false;
$list.each(function() {
var $item = $(this);
var id = $item.find('.title a').attr('href').split('/').reverse()[0];
var $counts = $item.find('.counts'), first_retrieve = $item.find('.time var').attr('title');
w.$item = $item;
r###lt.push(new DummyMylistVideo({
id: id,
length: $item.find('.length').text(),
mylist_counter: $counts.find('.mylist  var').text().split(',').join(''),
view_counter:   $counts.find('.view    var').text().split(',').join(''),
num_res:        $counts.find('.comment var').text().split(',').join(''),
first_retrieve: first_retrieve,
thumbnail_url:  $item.find('.lazyimage').data('original'),
title:          $item.find('.title').text().trim(),
_info: {first_retrieve: first_retrieve, is_channel: true},
description_short: $item.find('.description').text().trim()
}));
});
if ($html.find('.pager .next:not(.disabled)').length > 0) {
hasNextPage = true;
}
return hasNextPage;
},
loadOwnerVideo = function(callback) {
if (!window.WatchController.isChannelVideo()) {
throw {message: 'チャンネル情報の取得に失敗しました', status: 'fail'};
}
var params = {
id: window.WatchController.getOwnerId(),
ownerName: window.WatchController.getOwnerName()
};
var def = new $.Deferred();
load(callback, params).then(function(r###lt) {
r###lt.sortItem(params.sort || 6, true);
if (typeof callback === 'function') callback(r###lt);
def.resolve(r###lt);
}, function() {
def.reject({message: 'チャンネル動画の取得に失敗しました', status: 'fail'});
});
return def.promise();
};
var self = {
load: load,
loadOwnerVideo: loadOwnerVideo
};
window.WatchItLater.ChannelVideo = self;
return self;
})(w, Util);
var niconicodoRedirect = function() {
// www.nicovideo.jp/stampを watchにパラメータを中継するためのクッションページとして使う。
// watchと同じドメインならどこでもいいけど、ここはDBアクセスもなさそうな静的ページため採用
var hash = location.hash.toString();
if (hash.indexOf('#json={') !== 0) {
return;
}
console.log('%cNiconicodo redirect', 'background: lightgreen;');
LocationHashParser.initialize();
var blankWatchId = 'sm20353707';
var redirectWatchId = LocationHashParser.getValue('redirectWatchId');
// 見た目が残念なので消す
document.body.innerHTML = '';
window.sessionStorage.setItem('watchItLater_redirectedHash', location.hash);
var redirectTo = '/watch/' + (redirectWatchId ? redirectWatchId : blankWatchId);
location.replace(redirectTo);
};
function initZenzaWatchConnector() {
if (window !== top || !window.jQuery) { return; }
var onZenzaWatchFound = function(ZenzaWatch) {
window.console.log('%conZenzaWatchFound', 'background: lightgreen;');
ZenzaWatch.emitter.on('hideHover', function() {
AnchorHoverPopup.hidePopup();
});
ZenzaWatch.emitter.on('csrfTokenUpdate', function(token) {
//window.console.log('%ccsrfToken from ZenzaWatch: ', 'background: cyan;', token);
Mylist.setCsrfToken(token);
});
};
if (window.ZenzaWatch && window.ZenzaWatch.ready) {
onZenzaWatchFound(window.ZenzaWatch);
} else {
window.jQuery('body').on('ZenzaWatchReady', onZenzaWatchFound);
}
} //
window.setTimeout(initZenzaWatchConnector, 3000);
/**
*  GINZAwatch上でのあれこれ
*  無計画に増築中
*
*  watch.jsを解析すればわかる
*
*/
var ZeroFunc = function(w) { // Zero Watch
var
isTouchActive = false,
console = conf.debugMode ? window.console : {log: _.noop, trace: _.noop, time: _.noop, timeEnd: _.noop},
watchInfoModel = require('watchapp/model/WatchInfoModel').getInstance() || {};
if (!WatchApp.mixin) {
WatchApp.mixin = _.mixin;
}
console.log('%cGinza', 'background: lightgreen;');
/**
*  ゆっくり再生(スロー再生)メニュー
*/
var Yukkuri = (function($, conf, w) {
var self, $content = null, $button = null, timer = null, cnt = 0, isActive = false;
function createDom() {
$content = $('<div id="yukkuriPanel" />');
$button = $('<button>yu</button>').addClass('yukkuriButton').attr({title: 'ゆっくり(スロー再生)'});
$button.click(function() {
toggleActive();
});
$content.append($button);
$('body').append($content);
}
function show() {
if ($content === null) {
createDom();
}
updateView();
$content.show();
}
function hide() {
$content.hide();
}
function updateView() {
$button.toggleClass('active', isActive);
}
function start() {
if (timer !== null) {
clearInterval(timer);
}
isActive = true;
updateView();
timer = setInterval(function() {
var v = cnt++ % 4;
if (v === 0) {
WatchController.play();
} else
if (v === 1) {
WatchController.pause();
}
}, 20);
}
function stop() {
if (timer !== null) {
clearInterval(timer);
timer = null;
}
isActive = false;
updateView();
WatchController.pause();
}
function toggleActive() {
if (isActive) {
stop();
} else {
start();
}
return isActive;
}
self = {
show: show,
hide: hide,
start: start,
stop: stop
};
return self;
})($, conf, w);
function onWindowResizeEnd() {
setTimeout(function() {
EventDispatcher.dispatch('onWindowResizeEnd');
}, 1000);
}
/**
*  デフォルトの市場貼付ボタンはなぜかページの一番上までスクロールするという意地悪な仕様だが、
*  こっちはがんばって見やすい位置に調整して開く
*/
function ichibaSearch(word, shopCode) {
var wait = 10, opened = false;
//shopCode = shopCode || 'az'; // az = amazon
var search = function() {
if ($('#ichibaConsole').is(':visible')) {
setTimeout(function() {
var WindowUtil = require('watchapp/util/WindowUtil');
WindowUtil.scrollFitMinimum('#ichibaConsole', 300);
}, 1000);
if (!word) {
return;
}
if ($('#ichiba_search_form_query').is(':visible')) {
$('#ichiba_search_form_query').val(word);
w.ichiba.search(shopCode, 0, 'all');
setTimeout(function() {$('#ichiba_search_form_query').focus();}, 1000);
} else {
if (!opened) {
if(shopCode) { w.ichiba.showRelatedTagItems(shopCode, 0, 'all'); }
opened = true;
}
if (wait-- > 0) setTimeout(search, 1000);
}
} else {
if (wait-- > 0) setTimeout(search, 1000);
}
};
search();
w.ichiba.showConsole();
}
WatchController.ichibaSearch = ichibaSearch;
function initVideoCounter() {
var
PlayerInitializer = require('watchapp/init/PlayerInitializer'),
playerAreaConnector = PlayerInitializer.playerAreaConnector,
counter = {mylistCount: 0, viewCount: 0, commentCount: 0},
blinkItem = function($elm) {
$elm.removeClass('animateBlink').addClass('blink');
setTimeout(function() {
$elm.addClass('animateBlink').removeClass('blink');
$elm = null;
}, 500);
};
var setVideoCounter = function(watchId, title) {
var $tpl = $(
'<span>再生: <span class="viewCountDiff videoCountDiff"></span><span class="viewCount videoCount"></span> コメ: <span class="commentCountDiff videoCountDiff"></span><span class="commentCount videoCount"></span> マイ: <span class="mylistCountDiff  videoCountDiff"></span><span class="mylistCount videoCount"></span></span>'
);
assignVideoCountToDom($tpl, counter);
if ((conf.popupViewCounter === 'always') ||
(conf.popupViewCounter === 'full' && $('body').hasClass('full_with_browser'))
) {
Popup.show(
$('<div/>')
.append(
$('<a/>')
.text(window._.unescape(title))
.attr('href', 'http://nico.ms/' + watchId)
)
.html() +
'<br/><span style="margin-left:10px; font-size: 90%;">'+ $tpl.html() + '</span>'
);
}
$('#fullScreenToggleContainer').html([
'<img class="ownerIcon" src="', WatchController.getOwnerIcon(), '">',
'<div class="title">', title, '</div>',
'<p class="postedAt">',$('.videoPostedAt:last').text(), '</p>',
'<p class="videoCounter">', $tpl.html(), '</p>',
''].join(''))
.toggleClass('favorite', WatchController.isFavoriteOwner())
.find('img').attr('title', WatchController.getOwnerName());
if (conf.headerViewCounter) {
var vc = $('#videoCounter');
if (vc.length < 1) {
var li = $('<li></li>')[0];
li.id = 'videoCounter';
$('#siteHeaderLeftMenu').after(li);
vc = $('#videoCounter');
}
vc.empty().append($tpl);
}
};
playerAreaConnector.addEventListener('onWatchCountUpdated', function(c) {
var diff = c - counter.viewCount;
if (diff === 0) return;
counter.viewCount    = c;
EventDispatcher.dispatch('onVideoCountUpdated', counter, 'viewCount', diff);
});
playerAreaConnector.addEventListener('onCommentCountUpdated', function(c) {
var diff = c - counter.commentCount;
if (diff === 0) return;
counter.commentCount = c;
EventDispatcher.dispatch('onVideoCountUpdated', counter, 'commentCount', diff);
});
playerAreaConnector.addEventListener('onMylistCountUpdated', function(c) {
var diff = c - counter.mylistCount;
if (diff === 0) return;
counter.mylistCount  = c;
EventDispatcher.dispatch('onVideoCountUpdated', counter, 'mylistCount', diff);
});
EventDispatcher.addEventListener('onWatchInfoReset', function(watchInfoModel){
counter.mylistCount  = watchInfoModel.mylistCount;
counter.viewCount    = watchInfoModel.viewCount;
counter.commentCount = watchInfoModel.commentCount;
setVideoCounter(watchInfoModel.v, watchInfoModel.title);
});
EventDispatcher.addEventListener('onVideoCountUpdated', function(c, type, diff) {
var $target = $('.sidePanel .videoInfo, #fullScreenMenuContainer, #videoCounter');
assignVideoCountToDom($target, c);
$target.find('.' + type + 'Diff').text(diff).toggleClass('down', diff < 0);
blinkItem($target.find('.' + type + ', .' + type + 'Diff'));
});
} //
var isFirst = true;
function onVideoInitialized() {
//var TagInitializer = require('watchapp/init/TagInitializer');
AnchorHoverPopup.hidePopup().updateNow();
WatchCounter.add();
if (isFirst) {
if (conf.autoPlayIfWindowActive === 'yes' && w.document.hasFocus()) {
// ウィンドウがアクティブの時だけ自動再生する。 複数タブ開いてるときは便利
setTimeout(function() { WatchController.play(); }, 2000);
}
if (isFirst && conf.commentVisibility !== 'visible') {
if (conf.commentVisibility === 'hidden') {
console.log('comment off');
WatchController.commentVisibility(false);
} else {
console.log('last state', conf.lastCommentVisibility);
WatchController.commentVisibility(conf.lastCommentVisibility === 'visible');
}
}
EventDispatcher.dispatch('onFirstVideoInitialized');
}
EventDispatcher.dispatch('onVideoInitialized', isFirst);
isFirst = false;
} //
function onVideoChangeStatusUpdated(isChanging) {
var PlayerInitializer = require('watchapp/init/PlayerInitializer');
AnchorHoverPopup.hidePopup();
if (isChanging) {
$('.sidePanel .sideVideoInfo').removeClass('show');
}
if ((conf.enableAutoPlaybackContinue || conf.debugMode) && PlayerInitializer.noUserOperationController.autoPlaybackModel._isAutoPlayback) {
PlayerInitializer.noUserOperationController.autoPlaybackModel.setCount(0);
}
EventDispatcher.dispatch('onVideoChangeStatusUpdated', isChanging);
}
var $sideInfoPanelTemplate = $([
'<div class="sideVideoInfoInner">',
'<div class="videoTitleContainer"><h3 class="videoTitle"></h3></div>',
'<div class="videoOwnerInfoContainer">',
'<div class="channelIconContainer"><a target="_blank" class="channelIconLink">',
'<img class="channelIcon"></a>',
'<span class="channelName">提供: ',
'<a class="showOtherVideos" target="_blank"><span class="channelNameInner"></span></a></span>',
'</span>',
'</div>',
'<div class="userIconContainer"><a target="_blank" class="userIconLink">',
'<img class="userIcon"></a>',
'<span class="userName">投稿者: ',
'<span class="userNameInner notPublic"></span>',
'<span class="isPublic"><a class="showOtherVideos"><span class="userNameInner"></span></a></span>',
'</span>',
'</div>',
'</div>',
'<div class="videoInfo">',
'<span class="videoPostedAt"></span>',
'<ul class="videoStats">',
'<li style="position: relative;">再生: <span       class="viewCountDiff     videoCountDiff"></span><span class="videoCount viewCount"></span></li>',
'<li style="position: relative;">コメント: <span   class="commentCountDiff  videoCountDiff"></span><span class="videoCount commentCount"></span></li>',
'<li style="position: relative;">マイリスト: <span class="mylistCountDiff   videoCountDiff"></span><span class="videoCount mylistCount"></span></li>',
'</ul>',
'</div>',
'<div class="videoThumbnailContainer" style="display: none;">',
'<img class="videoThumbnailImage">',
'</div>',
'<div class="videoDetails">',
'<div class="videoDescription">',
'<div class="videoDescriptionInner">',
'</div>',
'</div>',
'</div>',
'</div>',
''].join(''));
// - 左パネル乗っ取る
function initLeftPanel($, conf, w) {
var $tab = $([
'<ul id="leftPanelTabContainer">',
'<li class="tab ichiba"    data-selection="ichiba"   >市場</li>',
'<li class="tab videoInfo" data-selection="videoInfo">情報</li>',
'</ul>'].join(''));
var
$sidePanel   = $('<div id="leftPanel" />').addClass('sidePanel'),
$infoPanel   = $('<div/>').attr({'id': 'leftVideoInfo',    'class': 'sideVideoInfo   sidePanelInner'}),
$ichibaPanel = $('<div/>').attr({'id': 'leftIchibaPanel',  'class': 'sideIchibaPanel sidePanelInner'});
$sidePanel.append($tab).append($infoPanel).append($ichibaPanel);
$('#playerTabWrapper').after($sidePanel);
var
onTabSelect = function(e) {
e.preventDefault();
AnchorHoverPopup.hidePopup();
var selection = $(e.target).attr('data-selection');
if (typeof selection === 'string') {
conf.setValue('lastLeftTab', selection);
changeTab(selection);
}
},
changeTab = function(selection) {
$sidePanel.removeClass('videoInfo ichiba').addClass(selection);
if (selection === 'ichiba') {
resetIchiba(false);
}
},
lastIchibaVideoId = '',
resetIchiba = function(force) {
var videoId = watchInfoModel.id;
if (lastIchibaVideoId === videoId && !force) {
return;
}
lastIchibaVideoId = videoId;
resetSideIchibaPanel($ichibaPanel, true);
},
resetScroll = function() {
$(this).animate({scrollTop: 0}, 600);
};
$infoPanel  .on('dblclick', resetScroll);
$ichibaPanel.on('dblclick', resetScroll);
$tab.on('click', onTabSelect).on('touchend', onTabSelect);
changeTab(conf.lastLeftTab);
var refreshPanel = function(isFirst) {
if (isFirst) { return; }
sidePanelRefresh($infoPanel, $ichibaPanel, $sidePanel, $sideInfoPanelTemplate.clone());
if ($ichibaPanel.is(':visible')) {
resetIchiba(true);
}
};
EventDispatcher.addEventListener('onVideoInitialized', refreshPanel);
refreshPanel();
} // end of initLeftPanel
function initRightPanel($, conf, w) {
var PlayerInitializer = require('watchapp/init/PlayerInitializer');
var $rightPanel = $('#playerTabWrapper').addClass('sidePanel');
initRightPanelVerticalTab($rightPanel);
initRightPanelHorizontalTab($, conf, w);
var $playerTabWrapper = $rightPanel, wideCss = null;
var
createWideCommentPanelCss = function (targetWidth) {
var px = targetWidth - $rightPanel.outerWidth();
var elms = [
'#playerTabWrapper', //'#playerTabWrapper',
'#commentDefaultHeader',
'#playerCommentPanel .commentTable',
'#playerCommentPanel .commentTable .commentTableContainer'
];
var css = [
'body.videoExplorer #content.w_adjusted #playerTabWrapper { width: ', targetWidth,'px; }\n',
'body:not(.full_with_browser) .w_wide #playerTabWrapper { width: ', targetWidth,'px; }\n',
'body:not(.videoExplorer):not(.full_with_browser) .w_wide #playerAlignmentArea             { width: 1100px; }\n', //  960 + 140
'body:not(.videoExplorer):not(.full_with_browser) .w_wide #playerAlignmentArea.size_normal { width: 1326px; }\n\n'  // 1186 + 140
];
for (var v in elms) {
var $e = $(elms[v]), newWidth = $e.width() + px;
css.push([
'.w_wide #playerTabWrapper ', elms[v],
' , body.videoExplorer #content.w_adjusted ',
elms[v], '\n{ width: ', newWidth,'px !important; }\n\n'
].join(''));
}
wideCss = addStyle(css.join(''), 'wideCommentPanelCss');
console.log(css.join(''));
},
toggleWide = function(v) {
$('#content').toggleClass('w_wide', v);
EventDispatcher.dispatch('onWindowResizeEnd');
};
var wideCommentPanelCss = Util.here(function() {/*
body.videoExplorer #content.w_adjusted #playerTabWrapper { width: 420px; }
body:not(.full_with_browser) .w_wide #playerTabWrapper   { width: 420px; }
body:not(.videoExplorer):not(.full_with_browser) .w_wide #playerAlignmentArea             { width: 1100px; }
body:not(.videoExplorer):not(.full_with_browser) .w_wide #playerAlignmentArea.size_normal { width: 1326px; }
body:not(.full_with_browser) .w_wide #playerTabWrapper #playerTabWrapper,
body.videoExplorer #content.w_adjusted #playerTabWrapper
{ width: 420px !important; }
body:not(.full_with_browser) .w_wide #playerTabWrapper #commentDefaultHeader,
body.videoExplorer #content.w_adjusted #commentDefaultHeader
{ width: 408px !important; }
body:not(.full_with_browser) .w_wide #playerTabWrapper #playerCommentPanel .commentTable,
body.videoExplorer #content.w_adjusted #playerCommentPanel .commentTable
{ width: 406px !important; }
body:not(.full_with_browser) .w_wide #playerTabWrapper #playerCommentPanel .commentTable .commentTableContainer,
body.videoExplorer #content.w_adjusted #playerCommentPanel .commentTable .commentTableContainer
{ width: 406px !important; }
*/});
addStyle(wideCommentPanelCss, 'wideCommentPanelCss');
EventDispatcher.addEventListener('on.config.wideCommentPanel', toggleWide);
toggleWide(!!conf.wideCommentPanel);
EventDispatcher.addEventListener('onFirstVideoInitialized', function() {
//EventDispatcher.dispatch('onWindowResizeEnd');
//createWideCommentPanelCss(420);
var $div = $([
'<div id="sharedNgSettingContainer" style="display: none;">NG共有: ',
'<select id="sharedNgSetting">',
'<option value="HIGH">高</option>',
'<option value="MIDDLE">中</option>',
'<option value="LOW">低</option>',
'<option value="NONE">無</option>',
'</select>',
'</div>',
''].join('')), $ngs = $div.find('select');
$ngs
.val(PlayerInitializer.nicoPlayerConnector.playerConfig.get().ngScoringFilteringLevel)
.on('change', function() {
var val = this.value;
PlayerInitializer.nicoPlayerConnector.playerConfig.set({ngScoringFilteringLevel: this.value});
});
$('#commentDefaultHeader').append($div);
EventDispatcher.addEventListener('on.config.enableSharedNgSetting', function(newValue, oldValue) {
if (newValue) {
$div.show();
} else {
$div.hide();
}
});
if (conf.enableSharedNgSetting) { $div.show(); }
});
} // end initRightPanel
function initRightPanelHorizontalTab($, conf, w) {
} //
function initRightPanelVerticalTab($sidePanel) {
if (!conf.rightPanelJack) { return; }
var PlayerInitializer = require('watchapp/init/PlayerInitializer');
var $tab = $([
'<ul id="sidePanelTabContainer">',
'<li class="tab comment"   data-selection="w_comment"  >コメント</li>',
'<li class="tab videoInfo" data-selection="w_videoInfo">動画情報</li>',
'<li class="tab ichiba"    data-selection="w_ichiba"   >ニコニコ市場</li>',
'<li class="tab review"    data-selection="w_review"   >レビュー</li>',
'</ul>'].join(''));
var $infoPanel   = $('<div/>').attr({'id': 'rightVideoInfo',   'class': 'sideVideoInfo   sidePanelInner'});
var $ichibaPanel = $('<div/>').attr({'id': 'rightIchibaPanel', 'class': 'sideIchibaPanel sidePanelInner'});
var $reviewPanel = $('<div/>').attr({'id': 'rightReviewPanel', 'class': 'sideReviewPanel sidePanelInner'});
$sidePanel.append($tab).append($infoPanel).append($ichibaPanel).append($reviewPanel);
var
onTabSelect = function(e) {
e.preventDefault();
AnchorHoverPopup.hidePopup();
var selection = $(e.target).attr('data-selection');
if (typeof selection === 'string') {
if (WatchController.isSearchMode()) {
conf.setValue('lastRightTabInExplorer', selection);
} else {
conf.setValue('lastRightTab',           selection);
}
changeTab(selection);
}
},
$videoReview = $('#videoReview'),
toggleReview = function(f) {
if (f) {
$reviewPanel.append($videoReview);
} else {
$('#rectangleAd').after($videoReview);
}
},
changeTab = function(selection) {
if ($sidePanel.hasClass('w_review') && selection !== 'w_review') {
toggleReview(false);
}
$sidePanel.removeClass('w_videoInfo w_comment w_ichiba w_review').addClass(selection);
if (selection === 'w_ichiba') {
resetIchiba(false);
} else
if (selection === 'w_review') {
toggleReview(true);
} else
if (selection === 'w_comment') {
setTimeout(function() {
var pv = require('watchapp/init/PlayerInitializer').rightSidePanelViewController.getPlayerPanelTabsView();
var cpv = pv._commentPanelView;
cpv.resize();
}, 500);
}
return changeTab;
},
lastIchibaVideoId = '', resetIchiba = function(force) {
var videoId = watchInfoModel.id;
if (lastIchibaVideoId === videoId && !force) {
return;
}
lastIchibaVideoId = videoId;
resetSideIchibaPanel($ichibaPanel, true);
},
resetScroll = function() {
$(this).animate({scrollTop: 0}, 600);
};
$infoPanel  .on('dblclick', resetScroll);
$ichibaPanel.on('dblclick', resetScroll);
$reviewPanel.on('dblclick', resetScroll);
$tab.on('click', onTabSelect).on('touchend', onTabSelect);
changeTab(conf.lastRightTab);
EventDispatcher.addEventListener('onVideoExplorerOpening', function() {
changeTab('w_comment');
});
EventDispatcher.addEventListener('onVideoExplorerClosing', function() {
changeTab(conf.lastRightTab);
});
var onOuterResize = function() {
var $body = $('body'), $right = $('#playerTabWrapper');
if (WatchController.isSearchMode() || $body.hasClass('full_with_browser')) { return; }
var w = $('#external_nicoplayer').outerWidth(), margin = 124;
w += $right.is(':visible') ? $right.outerWidth() : 0;
$('#sidePanelTabContainer').toggleClass('left', (window.innerWidth - w - margin < 0));
};
EventDispatcher.addEventListener('onWindowResizeEnd',           onOuterResize);
EventDispatcher.addEventListener('onPlayerAlignmentAreaResize', onOuterResize);
var refreshPanel = function(isFirst) {
window.setTimeout(function() {
$sidePanel
.toggleClass('reviewEmpty', $('#videoReview').find('.stream').length < 1)
.toggleClass('ichibaEmpty', WatchController.isIchibaEmpty());
}, 2000);
if (isFirst) { return; }
sidePanelRefresh($infoPanel, $ichibaPanel, $sidePanel, $sideInfoPanelTemplate.clone());
if ($ichibaPanel.is(':visible')) {
resetIchiba(true);
}
};
EventDispatcher.addEventListener('onVideoInitialized', refreshPanel);
refreshPanel();
} // end of initRightPanelVerticalTab
function assignVideoCountToDom($tpl, count) {
var addComma = require('watchapp/util/StringUtil').addComma;
$tpl
.find('.viewCount'   ).text(addComma(count.viewCount   )).end()
.find('.commentCount').text(addComma(count.commentCount)).end()
.find('.mylistCount' ).text(addComma(count.mylistCount ));
return $tpl;
} //
function sidePanelRefresh($sideInfoPanel, $ichibaPanel, $sidePanel, $template) {
var isFavorite = WatchController.isFavoriteOwner();
//var h = $sideInfoPanel.innerHeight() - 100;
$template.find('.videoTitle').html(watchInfoModel.title);
assignVideoCountToDom($template, watchInfoModel);
$template.find('.videoPostedAt').text($('.videoPostedAt:last').text());
var $videoDescription = $template.find('.videoDescription');
$videoDescription.find('.videoDescriptionInner').append(create$videoDescription(watchInfoModel.description));
var $userIconContainer       = $template.find('.userIconContainer');
var $channelIconContainer    = $template.find('.channelIconContainer');
var info = WatchController.getOwnerInfo();
if (info.type === 'channel') {
if (info.id && info.id !== '0') {
$channelIconContainer
.find('.channelIcon')
.attr({'src': info.icon}).end()
.find('.channelIconLink')
.attr({'href': info.page})
.on('click', Util.Closure.openVideoOwnersVideo()).end()
.find('.channelNameInner')
.text(info.name).end()
.find('.showOtherVideos')
.attr({'href': info.page})
.on('click', Util.Closure.openVideoOwnersVideo());
}
$userIconContainer.remove();
} else {
if (info.id && info.id !== '0') { // ユーザーが退会してたりすると情報が無いのでチェックしてから
$userIconContainer
.find('.userIcon')
.attr({'src': info.icon}).end()
.find('.userIconLink')
.attr({'href': info.page})
.on('click', Util.Closure.openVideoOwnersNicorepo()).end()
.find('.userNameInner')
.text(info.name).end()
.find('.showOtherVideos')
.attr({'href': info.page + '/video'})
.on('click', Util.Closure.openVideoOwnersVideo()   ).end()
.toggleClass('isUserVideoPublic', info.isVideoPublic);
$channelIconContainer.remove();
} else {
$userIconContainer.remove();
$channelIconContainer.remove();
}
}
$sideInfoPanel.find('*').unbind();
$sidePanel
.toggleClass('ichibaEmpty',    WatchController.isIchibaEmpty());
$sideInfoPanel
.empty()
.scrollTop(0)
.toggleClass('isFavorite', isFavorite)
.toggleClass('isChannel', WatchController.isChannelVideo())
.append($template);
window.setTimeout(function() {
$sideInfoPanel.addClass('show');
$sideInfoPanel = $ichibaPanel = $sidePanel = $template =
$videoDescription  = $userIconContainer =
$channelIconContainer = null;
}, 100);
} // end of sidePanelRefresh
/**
* 説明文中の動画リンク類を加工
*/
function decorateVideoDescriptionLink($description) {
var watchLinks = [], watchIds = [];
var videoReg = /\/watch\/((sm|nm|so|)\d+)$/;
var seigaReg = /seiga\/im(\d+)/;
$description.find('a').each(function() {
var url = this.href, text, $this = $(this);
if (videoReg.test(url)) {
var watchId = RegExp.$1;
var $videoLinkContainer = $([
'<div class="videoLinkContainer"></div>',
''].join(''));
var $nextButton = $([
'<div class="nextPlayButton" title="次に再生" onclick="WatchItLater.WatchController.insertVideoToPlaylist(\'', watchId, '\')">次に再生</div>',
''].join(''));
$this.after($videoLinkContainer);
$videoLinkContainer.append($this).append($nextButton);
watchLinks.push({id: watchId, $target: $videoLinkContainer});
watchIds.push(watchId);
} else if (seigaReg.test(url)) {
var illustId = RegExp.$1;
var $thumbnail = $([
'<div class="descriptionThumbnail illust">',
'<img src="http://lohas.nicoseiga.jp/thumb/',
illustId,
'z" onclick="WatchItLater.WatchController.showLargeThumbnail(this.src);">',
'</div>',
''].join(''));
$this.after($thumbnail);
}
});
if (conf.enableDescriptionThumbnail && watchIds.length > 0) {
var ac = function(s) {
var addComma = require('watchapp/util/StringUtil').addComma;
s = parseInt(s, 10);
s = s < 1 ? '-' : s;
return '<span class="count">' + addComma(s) + '</span>';
};
var onWatchIdInfoReady = function(r###lt) {
$(watchLinks).each(function(i, watchLink) {
var id = watchLink.id, $target = watchLink.$target;
if (r###lt[id]) {
var info = r###lt[id];
var $thmb = $([
'<div class="descriptionThumbnail video">',
'<img src="', info.thumbnail_url, '" onclick="WatchItLater.WatchController.showLargeThumbnail(this.src);">',
'<span class="uploadAt">', info.first_retrieve ,' 投稿</span>',
'<p>', info.title, ' (', info.length,  ')</p>',
'<div class="counterContainer">',
'<span class="view">再生: ',    ac(info.view_counter)  ,'</span> ',
'<span class="comment">コメ: ', ac(info.num_res)       ,'</span> ',
'<span class="mylist">マイ: ',  ac(info.mylist_counter),'</span>',
'</div>',
'</div>'].join(''));
$target.after($thmb);
}
$target = watchLink = null;
});
watchIds = watchLinks = null;
};
var onWatchIdInfoFail = function() {
watchIds = watchLinks = null;
};
window.setTimeout(function() {
window.WatchItLater.loader.videoArrayAPILoader.load(watchIds).then(onWatchIdInfoReady, onWatchIdInfoFail);
}, 1000);
} else {
watchIds = watchLinks = null;
}
$description = null;
}
/**
* 動画説明文のクリックイベント類を割り当てる
*/
function bindDescriptionEvents($description) {
$description.on('click', function(e) {
if (e.button !== 0 || e.metaKey || e.shiftKey || e.altKey || e.ctrlKey) { return; }
var elm = e.target;
if (elm.tagName !== 'A') { return; }
if (elm.className === 'otherSite') return;
var $elm = $(elm);
if (elm.textContent.indexOf('mylist/') === 0) {
e.preventDefault(); e.stopPropagation();
var mylistId = elm.textContent.split('/').reverse()[0];
WatchController.showMylist(mylistId);
} else
if (elm.className === 'seekTime') {
e.preventDefault(); e.stopPropagation();
var data = $elm.attr('data-seekTime').split(":"),
vpos = (data[0] * 60 + parseInt(data[1], 10)) * 1000;
WatchController.vpos(vpos);
}
});
$description.find('.watch').unbind('click');
$description = null;
}
function create$videoDescription(html) {
var linkmatch = /<a.*?<\/a>/, links = [], n;
html = html.split('<br />').join(' <br /> ');
while ((n = linkmatch.exec(html)) !== null) {
links.push(n);
html = html.replace(n, ' <!----> ');
}
// (htttp://example.com) -> ( htttp://example.com )  にして、 閉じカッコがリンクされるのを抑止
html = html.replace(/\((https?:\/\/[\x21-\x3b\x3d-\x7e]+)\)/gi, '( $1 )');
html = html.replace(/(https?:\/\/[\x21-\x3b\x3d-\x7e]+)/gi, '<a href="$1" target="_blank" class="otherSite">$1</a>');
for (var i = 0, len = links.length; i < len; i++) {
html = html.replace(' <!----> ', links[i]);
}
html = html.split(' <br /> ').join('<br />');
var $description = $('<p class="videoDescription description">' + html + '</p>');
bindDescriptionEvents($description);
decorateVideoDescriptionLink($description);
return $description;
} //
function resetSideIchibaPanel($ichibaPanel, force) {
$ichibaPanel.scrollTop(0).find('*').unbind().empty();
var $inner  = $('<div class="ichibaPanelInner" />');
var $header = $('<div class="ichibaPanelHeader"><p class="logo">ニコニコ市場出張所</p></div>');
$inner.append($header);
var items = [];
$('#ichibaMain').find('.ichiba_mainitem>div').each(function() {
var $item = $(this).clone().attr('id', null);
var $dl = $('<dl class="ichiba_mainitem" />').append($item);
$item.find('.thumbnail span').css({fontSize: ''});
// 誤クリックしやすいのでサムネはリンクを外す
$item.find('.thumbnail a img, .blomagaThumbnail, .blomagaText')
.parent().attr('href', null).attr('style', null).css({'text-decoration': 'none'});
$item.find('a').attr('onclick', null);
items.push($dl);
$inner.append($dl);
});
if (items.length > 0) {
for (var i = items.length -1; i >= 0; i--) {
$inner.find('#watch' + i + '_mq').attr('id', null).addClass('ichibaMarquee');
}
}
var $footer = $('<div class="ichibaPanelFooter"></div>');
var $addIchiba = $('<button class="addIchiba">商品を貼る</button>');
$addIchiba.click(function() {
AnchorHoverPopup.hidePopup();
ichibaSearch();
});
$footer.append($addIchiba);
var $reloadIchiba = $('<button class="reloadIchiba">リロード</button>');
$reloadIchiba.click(function() {
resetSideIchibaPanel($ichibaPanel, true);
$ichibaPanel = null;
});
$footer.append($reloadIchiba);
$inner.append($footer);
$inner.hide();
$ichibaPanel.append($inner);
$inner.fadeIn();
$inner = $header = $footer = $addIchiba = $reloadIchiba = null;
} //
function initHidariue() {
var PlayerInitializer = require('watchapp/init/PlayerInitializer');
// 再生終了時に勝手にメニューが開閉するのを止める
PlayerInitializer.videoendViewController.videoHeaderViewController = {openVideoMenu: function(){}, closeVideoMenu: function() {}};
var hidariue = null;
var resetHidariue = function() {
//        var dt = new Date();
//        if (dt.getMonth() < 1 && dt.getDate() <=1) {
//          $('#videoMenuTopList').append('<li style="font-size:50%"> \ │ /<br>  /‾\   /‾‾‾‾‾‾‾‾‾<br>─( ゜ ∀ ゜ )< しんねんしんねん!<br>  \_/   \_________<br> / │ \</li>');
//        }
if (!conf.hidariue) { return; }
if (!hidariue) {
$('#videoMenuTopList').append('<li class="hidariue" style="text-align: center;"><a href="http://userscripts.org/scripts/show/151269" target="_blank" style="color:black;"><img id="hidariue" style="border-radius: 8px; box-shadow: 1px 1px 2px #ccc;"></a><p id="nicodou" style="padding-left: 4px; display: inline-block"><a href="http://www.nicovideo.jp/video_top" target="_top"><img src="http://res.nimg.jp/img/base/head/logo/q.png" alt="ニコニコ動画:GINZA"></a></p></li>');
hidariue = $('#hidariue')[0];
}
hidariue.src = 'http://res.nimg.jp/img/base/head/icon/nico/' +
(1000 + Math.floor(Math.random() * 1000)).toString().substr(1) + '.gif';
};
EventDispatcher.addEventListener('onVideoInitialized', resetHidariue);
} //
var VideoExplorerToggleMenu;
WatchItLater.videoExplorerMenu = {};
WatchItLater.videoExplorerMenu.ToggleMenu = VideoExplorerToggleMenu = function(title, titleLink) {
this.initializeBaseDom(title, titleLink);
};
WatchApp.mixin(VideoExplorerToggleMenu.prototype, {
initializeBaseDom: function(title, titleLink) {
this._$toggle = $('<li style="display:none;" class="toggleVideoExplorerMenu watchItLaterMenu"></li>');
this._$menu   = $('<li class="slideMenu"><ul></ul></li>');
this._$list   = this._$menu.find('ul');
var $a = $('<a/>').text(title).attr('href', titleLink);
this._$toggle.append($a);
this._initializeToggleEvent();
this._initializeItemEvent();
},
_initializeToggleEvent: function() {
this._$toggle.on('click', $.proxy(function(e) {
if (e.button !== 0 || e.metaKey || e.shiftKey || e.altKey || e.ctrlKey) { return; }
e.preventDefault(); e.stopPropagation();
var isVisible = this._$menu.hasClass('open');
this._$toggle.addClass('opening');
this._$menu.toggleClass('open', !isVisible);
window.setTimeout($.proxy(function() {
this._$toggle.toggleClass('open', !isVisible);
this._$toggle.removeClass('opening');
}, this), 500);
}, this));
},
_initializeItemEvent: function() {
this._$menu.on('click', function(e) {
if (e.button !== 0 || e.metaKey || e.shiftKey || e.altKey || e.ctrlKey) { return; }
var elm = e.target;
if (elm.tagName !== 'A') { return; }
var $elm = $(elm);
var type = $elm.attr('data-menu-type');
if (type === 'mylist') {
e.preventDefault(); e.stopPropagation();
var mylistId = $elm.attr('data-mylist-id');
WatchController.showMylist(mylistId);
} else
if (type === 'deflist') {
e.preventDefault(); e.stopPropagation();
WatchController.showDeflist();
} else
if (type === 'tag') {
e.preventDefault(); e.stopPropagation();
var tag = $elm.attr('data-search-tag');
WatchController.nicoSearch(tag, 'tag');
}
});
},
attach: function() {
$('.videoExplorerMenu').find('ul:first li:first').after(this._$menu).after(this._$toggle);
},
detach: function() {
this._$toggle.detach();
this._$menu.detach();
},
add$listItem: function($item) {
this._$list.append($item);
},
addItem: function(name, title, attr, iconType) {
var
$a = $('<a/>')
.attr(attr)
.text(title),
$li = $('<li/>').addClass(iconType || '');
$li.append($a);
this._$list.append($li);
return $a;
},
addMylistItem: function(name, mylistId, title, iconType) {
var
$a = $('<a/>')
.text(name)
.attr({
href: '/mylist/' + mylistId,
title: title,
'data-menu-type': 'mylist',
'data-mylist-id': mylistId,
}),
$li = $('<li/>').addClass(iconType || '');
$li.append($a);
this._$list.append($li);
return $a;
},
show: function() {
this._$toggle.fadeIn(500);
}
});
WatchItLater.videoExplorerMenu.favMylists = (function() {
var toggleMenu;
var initialize = function() {
initialize = window._.noop;
console.log('%cinitialize WatchItLater.videoExplorerMenu.favMylists', 'background: lightgreen;');
toggleMenu = new VideoExplorerToggleMenu('お気に入りマイリスト', '/my/fav/mylist');
window.WatchItLater.loader.favMylists.load(function(mylists) {
if (mylists.length < 1) {
return;
}
for (var i = 0, len = mylists.length; i < len; i++) {
var mylist = mylists[i], lastVideo = mylist.lastVideo, $li = $('<li/>'),
title = [
'/mylist/', mylist.id, '\n',
mylist.description, '\n',
'最新動画: ', lastVideo.title, '\n',
'投稿日時: ', lastVideo.postedAt, '\n',
''].join('');
toggleMenu.addMylistItem(
mylist.name,
mylist.id,
title,
mylist.iconType
);
}
toggleMenu.show();
});
};
return {
attach: function() {
initialize();
toggleMenu.attach();
},
detach: function() {
if (!toggleMenu) {
return;
}
toggleMenu.detach();
}
};
})();
WatchItLater.videoExplorerMenu.favTags = (function() {
var toggleMenu;
var initialize = function() {
initialize = window._.noop;
console.log('%cinitialize WatchItLater.videoExplorerMenu.favTags', 'background: lightgreen;');
toggleMenu = new VideoExplorerToggleMenu('お気に入りタグ', '/my/fav/tag');
window.WatchItLater.loader.favTags.load(function(tags) {
if (tags.length < 1) {
$toggle.remove();
return;
}
var sortOrder = '?sort=' + conf.searchSortType + '&order=' + conf.searchSortOrder;
for (var i = 0, len = tags.length; i < len; i++) {
var tag = tags[i], $li = $('<li/>'),
$a = $('<a/>')
.attr({
href: '/tag/' + encodeURIComponent(tag.name + ' ' + conf.defaultSearchOption) + sortOrder,
'data-menu-type': 'tag',
'data-search-tag': tag.name
})
.text(tag.name);
toggleMenu.add$listItem($li.append($a));
}
toggleMenu.show();
});
};
return {
attach: function() {
initialize();
toggleMenu.attach();
},
detach: function() {
if (!toggleMenu) {
return;
}
toggleMenu.detach();
}
};
})();
WatchItLater.videoExplorerMenu.myShortcuts = (function() {
var toggleMenu;
var initialize = function() {
initialize = window._.noop;
console.log('%cinitialize WatchItLater.videoExplorerMenu.myShortcuts', 'background: lightgreen;');
toggleMenu = new VideoExplorerToggleMenu('マイショートカット', '/my/mylist');
toggleMenu.attach();
window.WatchItLater.mylist.loadMylistList(function(mylistList) {
toggleMenu.add$listItem(
$('<li/>').append(
$('<a/>')
.addClass('defMylist')
.attr({href: '/my/mylist', 'data-menu-type': 'deflist'})
.text('とりあえずマイリスト')
));
var items = [
{id:  -1, href: '/my/history',      name: '視聴履歴'},
{id:  -2, href: '/recommendations', name: 'あなたにオススメの動画'},
{id: NicorepoVideo.REPO_ALL,    href: '/my/top/all',    name: '【ニコレポ】すべての動画'},
{id: NicorepoVideo.REPO_USER,   href: '/my/top/user',   name: '【ニコレポ】お気に入りユーザー'},
{id: NicorepoVideo.REPO_CHCOM,  href: '/my/top/chcom',  name: '【ニコレポ】チャンネル&コミュニティ'},
{id: NicorepoVideo.REPO_MYLIST, href: '/my/top/mylist', name: '【ニコレポ】お気に入りマイリスト'}
];
for (var v in items) {
var item = items[v];
toggleMenu
.addMylistItem(item.name, item.id)
.addClass('defMylist')
.attr({
href: item.href
});
}
for (var i = 0, len = mylistList.length; i < len; i++) {
var mylist = mylistList[i];
toggleMenu.addMylistItem(mylist.name, mylist.id, '', 'folder' + mylist.icon_id);
}
toggleMenu.show();
});
};
return {
attach: function() {
initialize();
toggleMenu.attach();
},
detach: function() {
if (!toggleMenu) {
return;
}
toggleMenu.detach();
}
};
})();
WatchItLater.videoExplorerMenu.videoRanking = (function() {
var toggleMenu;
var VideoRankingToggleMenu = function(title, titleLink) {
WatchApp.extend(this, VideoRankingToggleMenu, VideoExplorerToggleMenu, [title, titleLink]);
this._$menu.addClass('videoRankingList');
this.initializeCategoryToggleEvents();
};
WatchApp.mixin(VideoRankingToggleMenu.prototype, {
initializeCategoryToggleEvents: function() {
this._$menu.on('click', '.rankingCategoryToggle', function(e) {
e.preventDefault(); e.stopPropagation();
var $target = $(e.currentTarget), category = $target.attr('data-category');
var $popup  = $target.closest('.slideMenu');
var isClose = $popup.find('li.' + category).toggleClass('categoryClose').hasClass('categoryClose');
conf.setValue('rankingCategory_' + category + '_Close', isClose);
});
},
addRankingItem: function($, genre, id, name, category, term) {
var $a =
$('<a/>')
.attr({
href: '/ranking/fav/' + term + '/' + genre,
'data-menu-type': 'mylist',
'data-mylist-id': id
})
.text(name)
.addClass(genre);
var $li = $('<li/>');
if (genre === category) {
$li.addClass('isCategory'); // nameと同じならカテゴリランキング、違うならジャンルランキング
if (genre !== 'all' && genre !== 'g_politics' && genre !== 'r18') {
var $button = $([
'<button class="rankingCategoryToggle">',
'<span class="open" title="サブカテゴリを開く">▼</span>',
'<span class="close" title="サブカテゴリを閉じる">▲</span>',
'</button>'
].join(''));
$button.attr('data-category', category);
$li.append($button);
}
}
var isClose = conf.getValue('rankingCategory_' + category + '_Close');
$li
.toggleClass('categoryClose', isClose)
.attr({'data-genre': genre, 'data-category': category})
.addClass(category).addClass(genre)
.append($a);
this._$list.append($li);
return $a;
}
});
var initialize = function() {
initialize = window._.noop;
console.log('%cinitialize WatchItLater.videoExplorerMenu.videoRanking', 'background: lightgreen;');
toggleMenu = new VideoRankingToggleMenu('動画ランキング', '/ranking');
toggleMenu.attach();
// TODO: マジックナンバーを
toggleMenu.addRankingItem($, 'all',  -100, 'カテゴリ合算(毎時)',   'all', 'hourly');
toggleMenu.addRankingItem($, 'all', -1100, 'カテゴリ合算(24時間)', 'all', 'daily');
//      toggleMenu.addRankingItem($, 'all', -4100, 'カテゴリ合算(合計)',   'all', 'total');
var genreId = VideoRanking.getGenreId();
for (var genre in genreId) {
if (genre === 'all') { continue; }
var id = genreId[genre], name = VideoRanking.getGenreName(genre), category = VideoRanking.getCategory(id);
toggleMenu.addRankingItem($, genre, id, name, category, 'hourly');
}
window.setTimeout(function() { toggleMenu.show(); }, 100);
};
return {
attach: function() {
initialize();
toggleMenu.attach();
},
detach: function() {
if (!toggleMenu) {
return;
}
toggleMenu.detach();
}
};
})();
var WatchingVideoView = function() { this.initialize.apply(this, arguments); };
WatchingVideoView.prototype = {
_params: null,
_$view: null,
_watchInfoModel: null,
_type: null,
initialize: function(params) {
this._content           = params.content;
this._watchInfoModel    = params.watchInfoModel;
this._$view             = params.$view;
this._mylistController  = params.mylistController;
this._type              = params.type;
this._$title  = this._$view.find('.title');
this._$thumb  = this._$view.find('.thumbnail');
this._$add    = this._$view.find('.add');
this._$remove = this._$view.find('.remove');
this._$add   .on('click', $.proxy(this._onAddClick,    this));
this._$remove.on('click', $.proxy(this._onRemoveClick, this));
EventDispatcher.addEventListener('onWatchInfoReset', $.proxy(this.onVideoChange, this));
},
getView: function() {
return this._$view;
},
detach: function() {
this._$view.detach();
},
update: function() {
$('.videoExplorerBody').toggleClass('containsWatchingVideo', this._content.containsWatchId());
},
onVideoChange: function() {
this._$title.html(this._watchInfoModel.title);
this._$thumb
.attr('src', this._watchInfoModel.thumbnail)
.off('click').on('click', Util.Closure.showLargeThumbnail(this._watchInfoModel.thumbnail));
if (this._content.isActive()) {
this.update();
}
},
_setIsUpdating: function() {
this._$view.addClass('updating');
setTimeout($.proxy(this._clearIsUpdating, this), 3000);
},
_clearIsUpdating: function() {
this._$view.removeClass('updating');
},
_getIsUpdating: function() {
return this._$view.hasClass('updating');
},
_onAddClick: function() {
var watchId = WatchController.getWatchId();
this._setIsUpdating();
if (this._type === 'deflist') {
this._mylistController.addDeflistItem(watchId,              $.proxy(this._onMylistUpdate, this));
} else {
var mylistId = this._content.getMylistId();
this._mylistController.addMylistItem (watchId, mylistId,    $.proxy(this._onMylistUpdate, this));
}
},
_onRemoveClick: function() {
var watchId = WatchController.getWatchId();
this._setIsUpdating();
if (this._type === 'deflist') {
this._mylistController.deleteDeflistItem(watchId,           $.proxy(this._onMylistUpdate, this));
} else {
var mylistId = this._content.getMylistId();
this._mylistController.deleteMylistItem (watchId, mylistId, $.proxy(this._onMylistUpdate, this));
}
},
_onMylistUpdate: function(status, r###lt) {
if (status === 'ok') {
if (this._type === 'deflist') {
WatchController.clearDeflistCache();
}
} else {
Popup.alert('更新に失敗: ' + r###lt.error.description);
}
this._content.setFilter(null);
setTimeout(
$.proxy(function() {
//this._content.changeState({page: 1});
this.contentRefresh();
this._clearIsUpdating();
}, this), 500);
},
contentRefresh: function() {
var params = this._content.getParams();
params.page = 1;
this._content.changeState(params);
this._content.refresh({page: 1});
}
}; // end WatchingVideoView.prototype
var GrepOptionView = function() { this.initialize.apply(this, arguments); };
GrepOptionView.prototype = {
_params: null,
_$view:  null,
initialize: function(params) {
this._content    = params.content;
this._$view      = params.$view;
this._$form      = this._$view.find('form');
this._$input     = this._$view.find('.grepInput').attr('list', params.listName);
this._$community = this._$view.find('.community');
this._$alive     = this._$view.find('.alive');
this._$duration  = this._$view.find('.duration');
this._$invert    = this._$view.find('.invert');
this._$checkboxes = this._$view.find('input[type=checkbox]');
this._$selectors  = this._$view.find('select');
this._not = false;
this._$view.toggleClass('debug', !!conf.debugMode);
this._$list = $('<datalist />').attr('id', params.listName);
$('body').append(this._$list);
this._$form.on('submit', $.proxy(this._onFormSubmit, this));
this._$checkboxes.on('click', $.proxy(this._onCheckClick, this));
this._$selectors
.on('click',  $.proxy(this._onSelectorClick, this))
.on('change', $.proxy(this._onSelectorChange, this));
this._$input.on('click', $.proxy(function(e) {
e.stopPropagation();
}, this))   .on('focus', $.proxy(function(e) {
var WindowUtil = require('watchapp/util/WindowUtil');
WindowUtil.scrollFit('#videoExplorer');
}, this));
this._$view .on('click', $.proxy(function(e) {
this._$input.focus();
}, this));
},
getView: function() {
return this._$view;
},
detach: function() {
this._$view.detach();
},
clear: function() {
this._$input.val('');
this._$checkboxes.prop('checked', false);
this._$view.removeClass('active');
this._$selectors.val('');
},
update: function() {
var list = this._content.getRawList();
var tmp = [];
for (var i = list.length -1; i >= 0; i--) {
tmp.push('<option>');
tmp.push(list[i].title); // 既にエスケープされてる
tmp.push('</option>');
}
this._$list.html(tmp.join(''));
if (this._getWord().length > 0) {
window.setTimeout($.proxy(function() { this._$input.focus(); }, this), 100);
}
},
_isActive: function() {
return (this._$input.val().length > 0 ||
!!this._$community.prop('checked') ||
!!this._$duration.val() ||
!!this._$alive    .prop('checked'));
},
_getWord: function() {
return $.trim(this._$input.val());
},
_onCheckClick: function(e) {
e.stopPropagation();
this._submit();
},
_onSelectorClick: function(e) {
e.stopPropagation();
},
_onSelectorChange: function(e) {
e.stopPropagation();
this._submit();
},
_onFormSubmit: function(e) {
e.preventDefault();
e.stopPropagation();
this._submit();
},
_submit: function() {
var isActive = this._isActive();
this._$view.toggleClass('active', isActive);
if (isActive) {
this._content.setFilter(this._getFilter());
} else {
this._content.setFilter(null);
}
this.contentRefresh();
},
contentRefresh: function() {
var params = this._content.getParams();
params.page = 1;
this._content.changeState(params);
this._content.refresh({page: 1});
},
_getFilter: function() {
var to_h = function(str) {
var m = new RegExp(window.unescape('"%5B%uFF21-%uFF3A%uFF41-%uFF5A%uFF10-%uFF19%5D"'), 'g');
return str.replace(m, function(s) {
return String.fromCharCode(s.charCodeAt(0) - 65248);
}).toLowerCase();
};
var word = to_h(this._getWord());
var communityReg = /^so|^\d+$/;
var wordFilter      = word.length > 0;
var durationVal     = parseInt(this._$duration.val(), 10);
var communityFilter = !!this._$community.prop('checked');
var aliveFilter     = !!this._$alive.prop('checked');
var durationFilter  = !isNaN(durationVal);
var isInvert        = !!this._$invert.prop('checked');
var isCommunity = function(item) {
return communityReg.test(item.id);
};
var isMatch = function(item) {
var title = item.title;
var desc  = item.description_full || item.description_short || '';
var mc    = item.mylist_comment   || '';
var text  = to_h([title, desc, mc].join('\n'));
return text.indexOf(word) >= 0;
};
var isAlive = function(item) {
var thumbnail = item.thumbnail_url || '';
if (thumbnail.indexOf('http://res.nimg.jp/img/common/video_deleted') < 0) {
return true;
}
return false;
};
var durationMatch = function(item) {
var itemDuration;
if (item.length_seconds) {
itemDuration = item.length_seconds;
} else {
var tmp = item.length.split(':');
itemDuration = parseInt(tmp[0], 10) * 60 + parseInt(tmp[1], 10);
}
if (durationVal < 0) {
return itemDuration <= Math.abs(durationVal);
} else {
return itemDuration >= durationVal;
}
};
var grepFilter = function(item) {
var r###lt = true, i = func.length, f;
while (--i >= 0 && (r###lt || isInvert)) {
f = func[i];
r###lt &= f(item);
}
return isInvert ? !r###lt : r###lt;
};
var func = [], f;
if (wordFilter)      { func.push(isMatch); }
if (communityFilter) { func.push(isCommunity); }
if (aliveFilter)     { func.push(isAlive); }
if (durationFilter)  { func.push(durationMatch); }
if (func.length < 1) { return null; }
return grepFilter;
}
}; // end GrepOptionView.prototype
function initMylistContent($, conf, w) {
var VideoExplorerInitializer = require('watchapp/init/VideoExplorerInitializer');
var ContentType      = require('watchapp/components/videoexplorer/model/ContentType');
var SearchSortOrder  = require('watchapp/components/nicosearchstatus/model/SearchSortOrder');
var ContentView      = require('watchapp/components/videoexplorer/view/content/MylistVideoContentView');
var vec      = VideoExplorerInitializer.videoExplorerController;
var explorer = vec.getVideoExplorer();
var myUserId = WatchController.getMyUserId();
var content = explorer.getContentList().getContent(ContentType.MYLIST_VIDEO);
var loader  = content._mylistVideoAPILoader;
var pager   = content._pager;
var watchingVideoView = new WatchingVideoView({
content: content,
watchInfoModel: watchInfoModel,
mylistController: Mylist,
type: 'mylist',
$view: $([
'<div class="watchingVideo">',
'<img class="thumbnail">',
'<p class="title"></p>',
'<span class="contains"    >この動画はリストに登録されています</span>',
'<span class="not_contains">この動画はリストにありません</span>',
'<span class="edit">',
'<button class="add"   >登録</button>',
'<button class="remove">外す</button>',
'</span>',
'</div>',
''].join(''))
});
var grepOptionView = new GrepOptionView({
content: content,
listName: 'suggestMylistTitle',
$view: $([
'<div class="grepOption">',
'<form>',
'<input type="search" class="grepInput" autocomplete="on" placeholder="タイトル・説明文で絞り込む(G)" accesskey="g">',
'<label class="communityFilter filter"><input type="checkbox" class="community">チャンネル・コミュニティ・マイメモリーのみ</label>',
'<label class="aliveFilter filter"><input type="checkbox" class="alive">生存動画のみ</label>',
'<label class="durationFilter filter">',
'動画時間<select class="duration">',
'<option value="">指定無し</option>',
'<option value="-180">3分以内</option>',
'<option value="180" >3分以上</option>',
'<option value="-300">5分以内</option>',
'<option value="300" >5分以上</option>',
'<option value="-600">10分以内</option>',
'<option value="600" >10分以上</option>',
'<option value="-1800">30分以内</option>',
'<option value="1800" >30分以上</option>',
'</select>',
'</label>',
'<label class="invertFilter filter"><input type="checkbox" class="invert">絞り込みの反転</label>',
'</form>',
'</div>',
].join(''))
});
pager._pageItemCount = conf.searchPageItemCount;
pager._displayPageCount = 5;
EventDispatcher.addEventListener('on.config.searchPageItemCount', function(v) {
pager._pageItemCount = v;
});
content._isOwnerNicorepo = false;
content._isRanking       = false;
content.getIsMine          = $.proxy(function() {
return parseInt(this.getUserId(), 10) === parseInt(myUserId, 10) && parseInt(this.getMylistId(), 10) > 0;
}, content);
content.getIsDummy         = $.proxy(function() {
var id = this.getMylistId();
return parseInt(id, 10) <= 0 || id.toString().indexOf('repo') === 0;
}, content);
content.getIsOwnerNicorepo = $.proxy(function() { return this._isOwnerNicorepo; }, content);
content.getIsRanking       = $.proxy(function() { return this._isRanking;       }, content);
// grep対応のための拡張
content._rawList = [];
content.getRawList    = $.proxy(function() { return this._rawList; }, content);
content._filter = null;
content.setFilter     = $.proxy(function(filter) {
this._filter = filter;
}, content);
content.getFilter     = $.proxy(function()       { return this._filter; }, content);
advice.around(content, 'clear', function(clear) {
this.setFilter(null);
clear.call(this);
grepOptionView.clear();
});
content.getNickname = $.proxy(function() {
if (this._nickname && this._nickname.length > 0) {
return this._nickname;
}
return 'no-name';
}, content);
//content.onLoad_org = content.onLoad;
advice.around(content, 'onLoad', function(onLoad, err, r###lt) {
this._isOwnerNicorepo = r###lt.isOwnerNicorepo;
this._isRanking       = r###lt.isRanking;
var filter = this.getFilter();
if (err === null && r###lt.list && r###lt.list.length) {
EventDispatcher.dispatch('mylistDataLoad', this.getMylistId(), r###lt);
if (!r###lt.rawList) r###lt.rawList = r###lt.list.concat();
if (filter) {
var list = [];
for (var i = r###lt.rawList.length - 1; i >= 0; i--) {
var item = r###lt.rawList[i];
if (item.title && filter(item)) {
list.unshift(item);
}
}
r###lt.list    = list;
} else {
r###lt.list = r###lt.rawList.concat();
}
} else
if (r###lt.rawList) {
r###lt.list = r###lt.rawList.concat();
}
this._rawList = r###lt.rawList || [];
onLoad.call(this, err, r###lt);
if (this.getIsMine()) {
EventDispatcher.dispatch('myMylistLoad', this.getMylistId(), {
name: this.getName(),
items: r###lt.rawList
});
}
});
content.containsWatchId = $.proxy(function(watchId) {
var list = this.getRawList();
if (!watchId) { watchId = WatchController.getWatchId(); }
for (var i = list.length - 1; i >= 0; i--) {
if (list[i].id === watchId) { return true; }
}
return false;
}, content);
var MylistLoadHookEvent = function(params) {
this.params = params;
this.data = null;
};
MylistLoadHookEvent.prototype.cancel = function(data) {
this.data = data;
};
//loader.load_org = loader.load;
advice.around(loader, 'load', function(load, params, callback) {
var isOwnerNicorepo = false, isRanking = false;
var id = params.id;
if (typeof id === 'string' && id.indexOf('repo-owner-') === 0) {
id = NicorepoVideo.REPO_OWNER;
}
var applyFilter = function(err, r###lt) {
r###lt.isOwnerNicorepo = isOwnerNicorepo;
r###lt.isRanking       = isRanking;
callback(err, r###lt);
};
// 外部スクリプトがダミーマイリストを流し込みたい場合はこのイベントをフック
var hook = new MylistLoadHookEvent(params);
EventDispatcher.dispatch('beforeMylistLoad', hook);
if (hook.data) {
applyFilter(null, hook.data);
return;
} else
if (id >= 0) {
load.call(this, params, applyFilter);
return;
}
var timeoutTimer = null;
var onload = function(r###lt) {
window.clearTimeout(timeoutTimer);
// 投稿者ニコレポが0件で、投稿動画一覧を公開していたらそっちを開くタイマーをセット
if (r###lt.list.length < 1 &&
parseInt(id, 10) === NicorepoVideo.REPO_OWNER &&
WatchController.isVideoPublic()) {
window.setTimeout(function() {
WatchController.openVideoOwnersVideo();
}, 500);
}
applyFilter(null, r###lt);
};
var onerror = function(r###lt) {
window.clearTimeout(timeoutTimer);
callback('error', r###lt);
};
timeoutTimer = window.setTimeout(function() {
onload = onerror = window._.noop;
onerror({message: '通信がタイムアウトしました:' + id, status: 'fail'});
}, 30 * 1000);
// マイリストIDに負の数字(通常ないはず)が来たら乗っ取るサイン
// そもそもマイリストIDはstringのようなので数字にこだわる必要なかったかも
//
try {
if (typeof VideoRanking.getGenreName(id) === 'string') {
isRanking = true;
VideoRanking.load(null, {id: id}).then(onload, onerror);
return;
}
// TODO: マジックナンバーを
switch (parseInt(id, 10)) {
case -1:
VideoWatchHistory.load(onload);
break;
case -2:
VideoRecommendations.load(onload);
break;
case -3:
ChannelVideoList.loadOwnerVideo(null).then(onload, onerror);
break;
case NicorepoVideo.REPO_ALL:
NicorepoVideo.loadAll()   .then(onload, onerror);
break;
case NicorepoVideo.REPO_USER:
NicorepoVideo.loadUser()  .then(onload, onerror);
break;
case NicorepoVideo.REPO_CHCOM:
NicorepoVideo.loadChCom() .then(onload, onerror);
break;
case NicorepoVideo.REPO_MYLIST:
NicorepoVideo.loadMylist().then(onload, onerror);
break;
case NicorepoVideo.REPO_OWNER:
isOwnerNicorepo = true;
NicorepoVideo.loadOwner() .then(onload, onerror);
break;
default:
throw {message: '未定義のIDです:' + id, status: 'fail'};
}
} catch(e) {
// TODO: ここのエラーをちゃんと投げる
if (e.message && e.status) {
onerror({
status: e.status,
message: e.message
});
} else {
console.log(e); console.trace();
onerror({message: 'エラーが発生しました:' + id, status: 'fail'});
}
}
});
var __css__ = Util.here(function() {/*
#videoExplorer .watchingVideo         { display: none; }
#videoExplorer .watchingVideo .title  { display: none; }
#videoExplorer .watchingVideo.updating * {
cursor: wait; opacity: 0.5;
}
#videoExplorer .watchingVideo button {
padding: 2px 12px; margin: 12px 24px;
}
#videoExplorer .isMine .watchingVideo {
display: block; background: #f4f4f4; border: 1px solid #ccc;
margin: auto; width: 500px; min-height: 48px; padding: 16px;
}
#videoExplorer .watchingVideo .thumbnail {
float: left; width: 72px; margin-right: 24px; cursor: pointer;
}
#videoExplorer .watchingVideo .title {
font-weight: bolder;
}
#videoExplorer .watchingVideo .title::before { content: ''; }
#videoExplorer .watchingVideo .title::after  { content: ' '; }
#videoExplorer                        .watchingVideo .contains     { display: none;   }
#videoExplorer .containsWatchingVideo .watchingVideo .contains     { display: inline; }
#videoExplorer                        .watchingVideo .not_contains { display: inline; }
#videoExplorer .containsWatchingVideo .watchingVideo .not_contains { display: none;   }
#videoExplorer         .watchingVideo .edit { display: none; }
#videoExplorer .isMine .watchingVideo .edit { display: inline-block; }
#videoExplorer                        .watchingVideo .add { display: inline-block; }
#videoExplorer .containsWatchingVideo .watchingVideo .add { display: none; }
#videoExplorer                        .watchingVideo .remove{ display: none; }
#videoExplorer .containsWatchingVideo .watchingVideo .remove{ display: inline-block; }
.isMine .editFavorite {
display: none; {* 自分のマイリストにはお気に入り登録ボタンを出さない *}
}
.watchingVideo button {
cursor: pointer;
}
.grepOption {
padding: 16px;
width: 500px;
margin: 16px auto;
background: #f4f4f4; border: 1px solid #ccc;
}
.grepOption .grepInput {
font-size: 120%;
width: 100%;
}
.grepOption .filter {
display: block; margin: 8px;
}
.grepOption .filter:hover {
background: #ccc;
}
.grepOption .filter.invertFilter {
display: none;
}
.grepOption.active .filter.invertFilter {
display: block; text-align: right;
}
*/});
addStyle(__css__, 'mylistContentCss');
var MylistDetailView = require('watchapp/components/videoexplorer/view/content/parts/MylistDetailView');
advice.after(MylistDetailView.prototype, 'update',
function(id, name, description, count) {
if (id.toString().match(/repo-owner-(\d+)/)) {
this._$name.attr('href', '/user/' + RegExp.$1);
} else
if (parseInt(id, 10) <= 0) {
this._$name.attr('href', '');
}
});
var
overrideContentView = function(proto, watchingVideoView, grepOptionView) {
var updateCssClass = function(content) {
$('.videoExplorerBody')
.toggleClass('dummyMylist',   content.getIsDummy())
.toggleClass('isMine',        content.getIsMine())
.toggleClass('ownerNicorepo', content.getIsOwnerNicorepo())
.toggleClass('ranking',       content.getIsRanking())
;
};
advice.after(proto, 'detach', function() {
watchingVideoView.detach();
grepOptionView.detach();
});
advice.after(proto, 'onUpdate', function() {
updateCssClass(this._content);
watchingVideoView.update();
grepOptionView.update();
this._$content.find('.mylistSortOrder').before(watchingVideoView.getView());
this._$content.find('.mylistSortOrder').before(grepOptionView.getView());
});
advice.after(proto, 'onError', function() {
updateCssClass(this._content);
watchingVideoView.update();
grepOptionView.update();
this._$content.find('.mylistSortOrder').before(grepOptionView.getView());
});
};
overrideContentView(ContentView.prototype, watchingVideoView, grepOptionView);
} // end initMylistContent
function initDeflistContent($, conf, w) {
var VideoExplorerInitializer = require('watchapp/init/VideoExplorerInitializer');
var ContentType = require('watchapp/components/videoexplorer/model/ContentType');
var ContentView = require('watchapp/components/videoexplorer/view/content/DeflistVideoContentView');
var vec         = VideoExplorerInitializer.videoExplorerController;
var explorer    = vec.getVideoExplorer();
var content     = explorer.getContentList().getContent(ContentType.DEFLIST_VIDEO);
var loader      = content._deflistVideoAPILoader;
var pager       = content._pager;
var watchingVideoView = new WatchingVideoView({
content: content,
watchInfoModel: watchInfoModel,
mylistController: Mylist,
type: 'deflist',
$view: $([
'<div class="watchingVideo">',
'<img class="thumbnail">',
'<p class="title"></p>',
'<span class="contains"    >この動画はリストに登録されています</span>',
'<span class="not_contains">この動画はリストにありません</span>',
'<span class="edit">',
'<button class="add"   >登録</button>',
'<button class="remove">外す</button>',
'</span>',
'</div>',
''].join(''))
});
var grepOptionView = new GrepOptionView({
content: content,
listName: 'suggestDeflistTitle',
$view: $([
'<div class="grepOption">',
'<form>',
'<input type="search" class="grepInput" autocomplete="on" placeholder="とりマイをタイトル・説明文で絞り込む(G)" accesskey="g">',
'<label class="communityFilter filter"><input type="checkbox" class="community">チャンネル・コミュニティ・マイメモリーのみ</label>',
'<label class="aliveFilter filter"><input type="checkbox" class="alive">生存動画のみ</label>',
'<label class="durationFilter filter">',
'動画長<select class="duration">',
'<option value="">指定無し</option>',
'<option value="-180">3分以内</option>',
'<option value="180" >3分以上</option>',
'<option value="-300">5分以内</option>',
'<option value="300" >5分以上</option>',
'<option value="-600">10分以内</option>',
'<option value="600" >10分以上</option>',
'<option value="-1800">30分以内</option>',
'<option value="1800" >30分以上</option>',
'</select>',
'</label>',
'<label class="invertFilter filter"><input type="checkbox" class="invert">絞り込みの反転</label>',
'</form>',
'</div>',
].join(''))
});
pager._pageItemCount = conf.searchPageItemCount;
pager._displayPageCount = 5;
EventDispatcher.addEventListener('on.config.searchPageItemCount', function(v) {
pager._pageItemCount = v;
});
content.changeState_org = content.changeState;
content.changeState = $.proxy(function(params, callback) {
if (!this.isActive()) {
WatchController.clearDeflistCache();
}
this.changeState_org(params, callback);
}, content);
content.getIsMine = function() { return true; };
// grep対応のための拡張
content._rawList = [];
content.getRawList    = $.proxy(function() { return this._rawList; }, content);
content._filter = null;
content.setFilter     = $.proxy(function(filter) {
this._filter = filter;
}, content);
content.getFilter     = $.proxy(function() { return this._filter; }, content);
content.onLoad_org = content.onLoad;
content.onLoad = $.proxy(function(err, r###lt) {
var filter = this.getFilter();
if (err === null && r###lt.list && r###lt.list.length) {
if (!r###lt.rawList) r###lt.rawList = r###lt.list.concat();
if (filter) {
var list = [];
for (var i = r###lt.rawList.length - 1; i >= 0; i--) {
var item = r###lt.rawList[i];
if (item.title && filter(item)) {
list.unshift(item);
}
}
r###lt.list    = list;
} else {
r###lt.list = r###lt.rawList.concat();
}
} else
if (r###lt.rawList) {
r###lt.list = r###lt.rawList.concat();
}
this._rawList         = r###lt.rawList || [];
this.onLoad_org(err, r###lt);
}, content);
content.clear_org = content.clear;
content.clear = $.proxy(function() {
this.setFilter(null);
this.clear_org();
grepOptionView.clear();
}, content);
content.containsWatchId = $.proxy(function(watchId) {
var list = this.getRawList();
if (!watchId) { watchId = WatchController.getWatchId(); }
for (var i = list.length - 1; i >= 0; i--) {
if (list[i].id === watchId) { return true; }
}
return false;
}, content);
var
overrideContentView = function(proto, watchingVideoView) {
var updateCssClass = function(content) {
$('.videoExplorerBody').toggleClass('isMine', true);
};
proto.detach_org = proto.detach;
proto.detach = function() {
this.detach_org();
watchingVideoView.detach();
grepOptionView.detach();
};
proto.onUpdate_org = proto.onUpdate;
proto.onUpdate = function() {
this.onUpdate_org();
updateCssClass(this._content);
watchingVideoView.update();
grepOptionView.update();
this._$content.find('.deflistSortOrder').before(watchingVideoView.getView());
this._$content.find('.deflistSortOrder').before(grepOptionView.getView());
};
proto.onError_org = proto.onError;
proto.onError = function() {
this.onError_org();
updateCssClass(this._content);
watchingVideoView.update();
grepOptionView.update();
this._$content.find('.deflistSortOrder').before(grepOptionView.getView());
};
};
overrideContentView(ContentView.prototype, watchingVideoView);
} // end initDeflistContent
function showLargeThumbnail(baseUrl) {
var largeUrl = baseUrl, size;
if (baseUrl.indexOf('smilevideo.jp') >= 0) {
largeUrl = baseUrl.replace(/\.([LM])/, '') + '.L';
size = 'width: 360px; height: 270px; max-height: 500px;';
} else {
largeUrl = baseUrl.replace(/z$/, 'l');
size = 'width: 360px; max-height: 500px;';
}
var
html = [
'<div class="largeThumbnailPopup" onmousedown="if (event.button == 0) { $(\'#popupMarquee\').removeClass(\'show\'); event.preventDefault(); }" style="width: 360px; height: 270px; background-image: url(' , largeUrl, ')">',
'<img src="', largeUrl, '" style="display: none;" onload="$(\'#popupMarquee .largeThumbnailPopup *\').hide()">',
//          '<img src="', baseUrl, '"  style="', size, ' z-index: 2;">',
'<div style="', size, ' background-image: url(' + baseUrl + '); "></div>',
'</div>',
''].join('');
Popup.show(html);
} //
WatchController.showLargeThumbnail = showLargeThumbnail;
function onVideoStopped() {
EventDispatcher.dispatch('onVideoStopped');
}
function onVideoEnded() {
EventDispatcher.dispatch('onVideoEnded');
}
var videoExplorerOpenCount = 0;
function onVideoExplorerOpened(params) {
window.console.timeEnd('onVideoExplorerOpen');
var target = params.target, contentList = params.contentList, content = params.content;
if (videoExplorerOpenCount++ === 0) {
EventDispatcher.dispatch('onFirstVideoExplorerOpened', content);
}
EventDispatcher.dispatch('onVideoExplorerOpened', content);
AnchorHoverPopup.hidePopup().updateNow();
}
function onVideoExplorerOpening(params) {
window.console.time('onVideoExplorerOpen');
var target = params.target, contentList = params.contentList, content = params.content;
if (videoExplorerOpenCount === 0) {
EventDispatcher.dispatch('onFirstVideoExplorerOpening', params);
}
EventDispatcher.dispatch('onVideoExplorerOpening', params);
}
function onVideoExplorerClosing(params) {
var target = params.target, contentList = params.contentList, content = params.content;
EventDispatcher.dispatch('onVideoExplorerClosing', content);
}
function onVideoExplorerClosed(params) {
var target = params.target, contentList = params.contentList, content = params.content;
AnchorHoverPopup.hidePopup().updateNow();
EventDispatcher.dispatch('onVideoExplorerClosed', content);
setTimeout(function() {
var PlaylistInitializer = require('watchapp/init/PlaylistInitializer');
PlaylistInitializer.playlistView.resetView();
$(window).resize();
}, 1000);
}
function onVideoExplorerRefreshStart(params) {
window.console.time('videoExplorerRefresh');
var target = params.target, contentList = params.contentList, content = params.content;
var
ContentType = require('watchapp/components/videoexplorer/model/ContentType'),
type = content.getType(),
$ve = $('#videoExplorer')
.removeClass('w_user').removeClass('w_upload').removeClass('w_mylist')
.removeClass('w_deflist').removeClass('w_related').removeClass('w_search'),
$body = $ve.find('.videoExplorerBody')
.removeClass('isMine').removeClass('dummyMylist')
.removeClass('isRanking').removeClass('isOwnerNicorepo'),
className = 'w_user';
switch (type) {
case ContentType.USER_VIDEO:
className = 'w_user';
break;
case ContentType.UPLOADED_VIDEO:
className = 'w_uploaded';
break;
case ContentType.MYLIST_VIDEO:
className = 'w_mylist';
break;
case ContentType.DEFLIST_VIDEO:
className = 'w_deflist';
break;
case ContentType.RELATED_VIDEO:
className = 'w_related';
break;
case ContentType.SEARCH:
className = 'w_search';
break;
}
$ve.addClass(className);
EventDispatcher.dispatch('onVideoExplorerRefreshStart', content);
}
function onVideoExplorerRefreshEnd(params) {
window.console.timeEnd('videoExplorerRefresh');
var target = params.target, contentList = params.contentList, content = params.content;
EventDispatcher.dispatch('onVideoExplorerRefreshEnd', content);
}
function onVideoExplorerChangePage(params) {
var target = params.target, contentList = params.contentList, content = params.content;
EventDispatcher.dispatch('onVideoExplorerChangePage', content);
}
/**
*  検索中の動画サイズを無理矢理でっかくするよ。
*/
var videoExplorerStyle = null, lastAvailableWidth = 0, lastBottomHeight = 0;
function adjustVideoExplorerSize(force) {
if (force !== true && (!conf.videoExplorerHack || !WatchController.isSearchMode())) { return; }
$('#videoExplorer, #content, #bottomContentTabContainer').toggleClass('w_adjusted', conf.videoExplorerHack);
var
isWindows = window.navigator.platform.toLowerCase().indexOf('win') >= 0,
scrollBarMargin = isWindows ? 16 : 0,
rightAreaWidth = $('.videoExplorerBody').outerWidth(), // 592
availableWidth = Math.max($(window).innerWidth() - rightAreaWidth, 300),
commentInputHeight = 30, //$('#playerContainer').hasClass('oldTypeCommentInput') ? 30 : 0,
controlPanelHeight = 46; //$('#playerContainer').hasClass('controll_panel') ? 46 : 0;
var
defPlayerWidth = 300, otherPluginsHeight = 0,
defPlayerHeight = (defPlayerWidth - 32) * 9 / 16 + 10,
ratio = availableWidth / defPlayerWidth , availableHeight = defPlayerHeight * ratio + commentInputHeight + controlPanelHeight,
xdiff = (availableWidth - defPlayerWidth /*- 20 */), windowHeight = $(window).innerHeight(),
bottomHeight = windowHeight - availableHeight - (WatchController.isFixedHeader() ? $('#siteHeader').outerHeight() : 0) - otherPluginsHeight;
if (ratio < 1 || availableWidth <= 0 || bottomHeight <= 0 || (lastAvailableWidth === availableWidth && lastBottomHeight === bottomHeight)) { return; }
var seekbarWidth = 675, scaleX = (availableWidth) / seekbarWidth;
lastAvailableWidth = availableWidth;
lastBottomHeight   = bottomHeight;
// コメントパネル召喚
var commentPanelWidth = 420;
var dynamic_css = [//'<style type="text/css" id="explorerHack">',
'body.videoExplorer #content.w_adjusted #playerContainerWrapper, \n',
'body.videoExplorer #content.w_adjusted #playerAlignmentArea, \n',
'body.videoExplorer #content.w_adjusted #playerContainer, \n',
'body.videoExplorer #content.w_adjusted #nicoplayerContainer ,\n',
'body.videoExplorer #content.w_adjusted #external_nicoplayer \n',
'{',
'width: ', availableWidth, 'px !important; height: ', availableHeight, 'px !important;padding: 0; margin: 0; ',
'}\n',
'body.videoExplorer #content.w_adjusted .videoExplorerMenu { ',
'position: absolute; width: 300px;',
'margin-top: ', availableHeight, 'px !important; left: ', (xdiff - 2), 'px; ',
'max-height: ', bottomHeight + 'px; overflow-y: auto; overflow-x: hidden; height: auto;',
'}\n',
'body.videoExplorer #videoExplorer.w_adjusted { ',
'margin-left: ', availableWidth,  'px !important;',
'min-height: ', (windowHeight + 200) ,'px !important;',
'overflow-x: hidden;',
' }\n',
'body.videoExplorer #content.w_adjusted #playlist { margin-left: ', xdiff, 'px; }\n',
'body.videoExplorer #content.w_adjusted #nicoHeatMap {',
'-webkit-transform: scaleX(', availableWidth / 100, ');',
'transform: scaleX(', availableWidth / 100, ');',
'}\n',
'body.videoExplorer #content.w_adjusted #nicoHeatMapContainer {',
'width: ', availableWidth, 'px;',
'}\n',
'body.videoExplorer #content.w_adjusted #smart_music_kiosk {',
'-webkit-transform: scaleX(', scaleX, ');',
'left: ', ((availableWidth - seekbarWidth) / 2) ,'px !important;',
'}\n',
'body.videoExplorer #content.w_adjusted #songrium_logo_mini {',
'left: ', (availableWidth + 5) ,'px !important;',
'}\n',
'body.videoExplorer #content.w_adjusted #inspire_category {',
'left: ', (availableWidth + 32) ,'px !important;',
'}\n',
'body.videoExplorer #content.w_adjusted #leftPanel {',
' display: block !important; top: ', (availableHeight + otherPluginsHeight - 1), 'px; max-height: ', bottomHeight, 'px; width: ', (xdiff - 4 + 1), 'px; left: 0;',
' height:', bottomHeight, 'px; display: block; border-radius: 0;',
'}',
'body.videoExplorer #content.w_adjusted #leftPanel .sideVideoInfo, body.size_small.no_setting_panel.videoExplorer #content.w_adjusted #leftPanel .sideIchibaPanel {',
'width: ', Math.max((xdiff -  4), 130), 'px; border-radius: 0;',
'}',
((xdiff >= 400) ?
[
'body.videoExplorer #content.w_adjusted #leftPanel .sideVideoInfo .videoTitleContainer{',
'margin-left: 158px; border-radius: 0 0 ;background: #ddd; border: solid; border-color: #ccc; border-width: 1px 1px 0;',
'}',
'body.videoExplorer #content.w_adjusted #leftPanel .sideVideoInfo .videoThumbnailContainer{',
'position: absolute; max-width: 150px; top: 0; ',
'}',
'body.videoExplorer #content.w_adjusted #leftPanel .sideVideoInfo .videoInfo{',
'background: #ddd; margin-left: 158px; border-radius: 0 0; border: solid; border-color: #ccc; border-width: 0 1px 1px;',
'}',
'body.videoExplorer #content.w_adjusted #leftPanel .sideVideoInfo .videoDetails{',
'margin-left: 158px; height: 100%; ',
'}',
'body.videoExplorer #content.w_adjusted #leftPanel .sideVideoInfo .videoOwnerInfoContainer{',
'position: absolute; width: 150px; top: 0; border: 1px solid #ccc; margin: 0;',
'}',
'body.videoExplorer #content.w_adjusted #leftPanel .sideVideoInfo .userIconContainer, body.videoExplorer #content.w_adjusted #leftPanel .sideVideoInfo .ch_profile{',
'background: #ddd; max-width: 150px; float: none; border-radius: 0;',
'}',
'body.videoExplorer:not(.content-fix) .w_adjusted .videoDetails, ',
'body.videoExplorer:not(.content-fix) .w_adjusted #videoExplorerMenu {',
// タグ#域三行分 bodyのスクロール位置をタグの場所にしてる時でもパネルは文章の末端までスクロールできるようにするための細工
// (四行以上あるときは表示しきれないが)
'padding-bottom: 72px; ',
'}',
].join('') :
(
(xdiff >= 154) ?
['body.videoExplorer #content.w_adjusted #leftPanel #leftPanelTabContainer { padding: 4px 2px 3px 2px; }'].join('') :
['body.videoExplorer #content.w_adjusted #leftPanel { display: none !important;}'].join('')
)
),
'body.videoExplorer #bottomContentTabContainer.w_adjusted .videoExplorerFooterAdsContainer { width: 520px; }\n',
'body.videoExplorer #content.w_adjusted #playerTabWrapper {',
'height: ', availableHeight, 'px !important;',
'}',
'body.videoExplorer #content.w_adjusted #playerTabWrapper .sidePanelInner {',
'height: ', (availableHeight - 2), 'px;',
'}',
'body.videoExplorer #content.w_adjusted #playerTabWrapper.w_active {',
'right: -',(commentPanelWidth - 2), 'px !important; top: 0 !important;  background: transparent; border: 0;  margin-top: 0px;',
'}',
'body.videoExplorer #content.w_adjusted #playerTabWrapper.w_active             #playerCommentPanel {',
'display: block; background: #dfdfdf; border: 1px solid;',
'}',
''].join('');
if (videoExplorerStyle) {
videoExplorerStyle.innerHTML = dynamic_css;
} else {
videoExplorerStyle = addStyle(dynamic_css, 'videoExplorerStyle');
}
} // end adjustVideoExplorerSize
function setupVideoExplorerStaticCss() {
var __css__ = Util.here(function() {/*
body.videoExplorerOpening {
overflow-y: scroll;
}
body.videoExplorerOpening .videoExplorerMenu {
{* display: none; *}
}
body.videoExplorerOpening #playerTabWrapper {
visibility: hidden;
}
#videoExplorer {
transition: margin-left 0.4s ease 0.4s; overflow-x: hidden;
}
#videoExplorer.w_adjusted .videoExplorerBody, #videoExplorer.w_adjusted .videoExplorerContent .contentItemList {
width: 592px; padding-left: 0; min-width: 592px; max-width: auto;
}
#videoExplorer.w_adjusted .searchBox {
width: 574px;\
}
#videoExplorer.w_adjusted .videoExplorerContent {
width: 592px;
}
#videoExplorer.w_adjusted .videoExplorerBody .r###ltContentsWrap {
width: 592px; padding: 16px 0px;
}
#videoExplorer.w_adjusted .videoExplorerMenu, #content .videoExplorerMenu:not(.initialized) { display: none; }
.videoExplorerMenu {
transition: margin-top 0.4s ease 0.4s; {*, left 0.4s ease-in-out*};
}
#leftPanel {
{* transition: width 0.4s ease 0.4s, height 0.4s ease 0.4s, top 0.4s ease 0.4s, left 0.4s ease 0.4s;*}
transition: width 0.4s ease 0.4s, height 0.4s ease 0.4s, left 0.4s ease 0.4s;
}
#content.w_adjusted #playlist {
min-width: 592px;
}
#content.w_adjusted .videoExplorerMenu:not(.w_touch) .itemList>li,  body.videoExplorer #content.w_adjusted #videoExplorerExpand {
height: 26px;
}
#content.w_adjusted .videoExplorerMenu:not(.w_touch) .itemList>li>a,body.videoExplorer #content.w_adjusted #videoExplorerExpand a{
line-height: 26px; font-size: 100%;
}
.errorMessage {
max-height: 0; line-height: 30px; overflow: hidden; text-align: center; color: #f88; cursor: pointer;
transition: max-height 0.8s ease;
}
.videoErrorOccurred .errorMessage {
max-height: 100px;
}
.w_adjusted .videoExplorerMenu .itemList li .arrow {
top: 8px;
}
.w_adjusted .videoExplorerMenu .closeVideoExplorer {
width: 300px; position: relative; padding: 2px 10px; background: #f5f5f5;
}
.w_adjusted .videoExplorerMenu .closeVideoExplorer:hover {
background: #dbdbdb;
}
.w_adjusted .videoExplorerMenu .closeVideoExplorer a{
display: block;line-height: 26px; {*color: #CC0000;*}
}
#searchR###ltNavigation > ul > li a::after, #content.w_adjusted #videoExplorerExpand a#closeSearchR###ltExplorer::after {
top: 8px;
}
#content.w_adjusted #playerContainerWrapper, #content.w_adjusted #playlist { box-shadow: none; }
#content.w_adjusted #videoExplorerExpand .arrow { display: none; }
body.videoExplorer #footer.w_adjusted {
display: none;
}
.w_adjusted .uadTagRelated .default .itemList .item .videoTitleContainer {
width: 130px;
text-align: center;
}
.w_adjusted .uadTagRelated .uadTagRelated {
margin-bottom: 30px;
}
.w_adjusted .uadTagRelated .itemList .item,
.w_adjusted .uadTagRelated .emptyItem,
.w_adjusted .uadTagRelated .default .landing {
width: 130px; margin: 0 10px 0 8px;
}
.w_adjusted .uadTagRelated .default .itemList .item .imageContainer .itemImageWrapper .itemImage {
width: 130px; height: auto; top: 0; left: 0;
}
.w_adjusted .uadTagRelated .default .itemList .item .imageContainer .itemImageWrapper {
width: 130px; height: 100px;
}
.w_adjusted .uadTagRelated .emptyItem .emptyMessageContainer {
width: 130px; height: 100px;
}
.w_adjusted .videoExplorerContent .column1 .videoInformationOuter .link,
.w_adjusted .videoExplorerContent .column1 .videoInformationOuter .link .title {
display: inline;
}
#videoExplorer.w_adjusted .videoExplorerContent .column1 .commentBlank {
width: 96%;
}
#videoExplorer.w_adjusted .videoExplorerContent .column4 .commentBlank {
width: 24%;
}
.videoExplorerBody .videoExplorerContent .contentItemList.column4 .item .createdTime .submit
{
display: none !important;
}
.nicorepoR###lt .column4 .videoInformation {
display: none;
}
#videoExplorer .pager { margin-right: 20px; }
#videoExplorer .contentItemList { clear: both; }
body.videoExplorer #content.w_adjusted #playerContainerWrapper { overflow: visible; }
body.videoExplorer #videoExplorer.w_adjusted .videoExplorerContent { padding: 20px 0px; }
body.videoExplorer #videoExplorer.w_adjusted .videoExplorerContentWrapper
{ margin-left: 0; padding: 20px 340px 20px 0px; }
body.videoExplorer.playlist #videoExplorer.w_adjusted .videoExplorerContentWrapper
{ margin-left: 0; padding: 164px 340px 20px 0px; }
{* 謎のスペーサー *}
{*body.videoExplorer #content.w_adjusted .videoExplorerMenu>div:first *}
{* body.videoExplorer #content.w_adjusted .videoExplorerMenu>div:not(.videoExplorerMenuInner) { display: none; } *}
body.videoExplorer #content.w_adjusted .videoExplorerMenu>div:nth-child(1) { display: none; }
body.videoExplorer #content.w_adjusted .videoExplorerMenu
{ width: 300px; }
body.videoExplorer #content.w_adjusted .videoExplorerMenuInner
{ position: static !important; top: 0 !important; left: 0 !important; }
body.videoExplorer #bottomContentTabContainer.w_adjusted { {*background: #ccc;*} }
body:not(.videoExplorer)      .videoExplorerMenu { display: none; }
body.videoExplorer #content.w_adjusted #nicoplayerContainer {
z-index: 100;
}
body.videoExplorer #content.w_adjusted #playerTabWrapper {
top: 0px !important; background: #dfdfdf; border-radius: 4px;
z-index: 99;
transition: right 0.3s ease-out;
}
#videoExplorer.w_adjusted .videoExplorerBody .videoExplorerContent .contentItemList.column1 .item {
margin-left: 8px;
}
#videoExplorer.w_adjusted .videoExplorerBody .videoExplorerContent .contentItemList.column4 .item {
width: 130px; margin-left: 8px; margin-right: 10px;
}
#videoExplorer.w_adjusted .videoExplorerBody .videoExplorerContent                 .column1 .videoInformationOuter {
width: 414px;
}
#videoExplorer.w_adjusted .videoExplorerBody .videoExplorerContent                 .column1 .nicorepoR###lt .videoInformationOuter {
width: auto;
}
#videoExplorer.w_adjusted .contentItemList .folder .column1 .description,
#videoExplorer.w_adjusted .suggestVideo    .folder .column1 .description,
#videoExplorer.w_adjusted .descriptionShort {
width: 410px;
}
#videoExplorer .descriptionShort {
line-height: 1.5;
margin: 0 0 4px;
word-break: break-all;
clear: both;
color: #666;
font-size: 93%;
}
.w_adjusted .column1 .smallThumbnail .createdTime.at {
width: 130px;
}
.w_adjusted .column1 .createdTime.at {
width: 160px; text-align: center;
}
.w_adjusted .createdTime {
white-space: nowrap;
}
#videoExplorer.w_adjusted .videoExplorerBody .videoExplorerContent .contentItemList .folder .container,
#videoExplorer.w_adjusted .videoExplorerBody .videoExplorerContent .suggestVideo .folder .container {
background-position: -15px -270px; width: 130px; height: 100px;
}
body.size_small.no_setting_panel.videoExplorer #content #videoExplorerExpand { {*「閉じる」ボタン *}
position: static; top: auto; left: auto; margin-top: 0;',
}
body.videoExplorer #content.w_adjusted #playerTabWrapper #playerCommentPanel {
display: none;
}
.videoExplorerMenu .item:hover {
background: #dbdbdb; text-decoration: underline;
}
.videoExplorerMenu .item {
position: relative; border-bottom: 1px solid #CCCCCC; background: #f2f2f2;
text-decoration: none; cursor: pointer;
}
.videoExplorerMenu .item .arrow {
display: block; position: absolute; top: 14px; right: 12px; width: 9px; height: 12px;
background: url("http://res.nimg.jp/img/watch_q9/video_explorer/icon_normal.png") no-repeat 0 0;
}
.videoExplorerMenu .item .text {
position: relative; width: 100%; height: 100%; display: block; text-align: left;
text-decoration: none; padding: 0 12px; color: #000; box-sizing: border-box;
line-height: 26px; -webkit-box-sizing: border-box; -moz-box-sizing: border-box;
}
.videoExplorerMenu .itemList>li:first {
position: relative;
}
#videoExplorer .videoExplorerMenu .closeVideoExplorer, #videoExplorer .quickSearchInput {
display: none;
}
#videoExplorer .videoExplorerBody .videoExplorerContent .contentItemList.column1 .video .column1 .videoInformationOuter .title
{
white-space: normal;
}
.videoExplorer #playlist {
transition: margin-left 0.4s ease 0.4s;
}
#playerAlignmentArea .toggleCommentPanel {
display: none;
position: absolute;
right: -119px;
bottom: 70px;
width: 100px;
height: 30px;
cursor: pointer;
outline: none;
background: #ccc;
border-radius: 16px 16px 0 0;
border: solid 1px black;
-webkit-transform: rotate(90deg); -webkit-transform-origin: 0 0 0;
transform: rotate(90deg);         transform-origin: 0 0 0;
transition: 0.4s ease-in-out;
-webkit-transition: 0.4s ease-in-out;
}
#playerAlignmentArea .toggleCommentPanel::-moz-focus-inner {
border: 0px;
}
body.videoExplorer .w_adjusted #playerAlignmentArea .toggleCommentPanel { display: block; }
#playerAlignmentArea .toggleCommentPanel::before {
content: '↑ ';
}
#playerAlignmentArea .toggleCommentPanel:hover {
right: -129px;
}
#playerAlignmentArea .toggleCommentPanel.w_active {
right: -418px;
bottom: -29px;
border-radius: 0 0 16px 16px;
z-index: 10000;
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
transition: none;
-webkit-transition: 0.4s ease-in-out;
{*transition: 0.4s ease-in-out;*}
}
#playerAlignmentArea .toggleCommentPanel.w_active:hover {
{*box-shadow: 2px 2px 2px #888;*}
right: -418px;
}
#playerAlignmentArea .toggleCommentPanel.w_active::before {
content: '← ';
}
.videoExplorerOpening .videoExplorerBody .videoExplorerConfig {
display: none;
}
.videoExplorerBody .videoExplorerConfig {
cursor: pointer;
width: 80px; margin-left: -36px; white-space: nowrap;
border-radius: 0 32px 0 0; border: solid 1px #666; border-width: 1px 1px 0;
color: #fff; background: #aaa;
}
#videoExplorer.w_adjusted       .videoExplorerConfig .open,
#videoExplorer:not(.w_adjusted) .videoExplorerConfig .close {
display: none;
}
.videoExplorerConfig::-moz-focus-inner { border: 0px; }
.videoExplorer #playerContainer.appli_panel #appliPanel {
width: auto !important; background: #333;
}
.videoExplorerContent {
background: #fff;
}
*/});
return addStyle(__css__, 'videoExplorerStyleStatic');
} // end setupVideoExplorerStaticCss
function initAutoComplete($searchInput) {
var
$suggestList = $('<datalist id="quickSearchSuggestList"></datalist>'),
wordSuggest = '',
favTagsSuggest = '',
loading = false,
val = '',
suggestLoader = new NicoSearchSuggest({}),
update = _.debounce(function() {
if (loading) {
return;
}
var value = $searchInput.val();
if (value.length >= 1 && val !== value) {
val = $searchInput.val();
loading = true;
suggestLoader.load(val, onSuggestLoaded);
} else {
loading = false;
}
}, 300),
onSuggestLoaded = function(err, r###lt) {
if (err) {
return;
}
if (r###lt.candidates) {
//console.log(r###lt.candidates);
var candidates = r###lt.candidates;
var options = [];
for (var i = candidates.length - 1; i >= 0; i--) {
options.unshift(['<option value="', candidates[i], '"></option>'].join(''));
}
wordSuggest = options.join('');
refresh();
}
loading = false;
},
refresh = function() {
$suggestList.html(wordSuggest + favTagsSuggest);
},
bind = function($elm) {
$elm
.on('focus',     update)
.on('keydown',   update)
.on('keyup',     update)
.on('keypress',  update)
.on('click',     update)
.on('mousedown', update)
.on('mouseup',   update)
.attr({'autocomplete': 'on', 'list': 'quickSearchSuggestList', 'placeholder': '検索ワードを入力(Q)'});
// try {
//   //$elm.attr('type', 'search');
//   //$elm[0].setAttribute('type', 'search');//.attr('type', 'search');
// } catch (e) {
//   console.log(e);
// }
};
EventDispatcher.addEventListener('onFavTagsLoad', function(tags) {
var options = [];
for (var i = tags.length - 1; i >= 0; i--) {
options.unshift(['<option value="', tags[i], '"></option>'].join(''));
}
favTagsSuggest = options.join('');
refresh();
});
$('body').append($suggestList);
bind($searchInput);
} //
function initVideoExplorer($, conf, w) {
setupVideoExplorerStaticCss();
var VideoExplorerInitializer = require('watchapp/init/VideoExplorerInitializer');
var WatchPageRouter = require('watchapp/model/state/WatchPageRouter');
var WatchPageState  = require('watchapp/model/state/WatchPageState');
var PlayerInitializer = require('watchapp/init/PlayerInitializer');
var WindowUtil = require('watchapp/util/WindowUtil');
var
_vp = 'watchapp/components/videoexplorer/',
initializer     = VideoExplorerInitializer,
controller      = VideoExplorerInitializer.videoExplorerController,
explorer        = controller.getVideoExplorer(),
explorerConfig  = require(_vp + 'config/VideoExplorerConfig'),
menu            = explorer.getMenu(),
ContentItemType = require(_vp + 'model/ContentItemType'),
ContentType     = require(_vp + 'model/ContentType'),
watchPageRouter = WatchPageRouter.getInstance(),
playerConnector = PlayerInitializer.nicoPlayerConnector,
searchType      = 'tag',
$menu           = $('.videoExplorerMenu'),
$searchInput    = $('<input class="quickSearchInput" type="search" name="q" accesskey="q" required="required" x-webkit-speech />')
.attr({'title': '検索ワードを入力', 'placeholder': '検索ワードを入力(Q)'}),
$closeExplorer  = $('<div class="closeVideoExplorer"><a href="javascript:;">▲ 画面を戻す</a></div>'),
$inputForm      = $('<form  action="javascript:void(0);" />').append($searchInput),
$toggleCommentPanel = $('<button class="toggleCommentPanel">コメント</button>');
// init search menu
$searchInput.on('keyup', function(e) {
$('.searchText input').val(this.value);
}).on('click', function(e) {
e.stopPropagation();
});
$inputForm.on('submit', function(e) {
//e.preventDefault();
var val = $.trim($searchInput.val());
if (val.length > 0) {
if (val.match(/(sm|nm|so)\d+/)) {
WatchController.nicoSearch(val, 'tag');
} else {
WatchController.nicoSearch(val, 'keyword');
}
}
});
var clearButton = new window.Nico.ClearButton({targetInput: $searchInput});
EventDispatcher.addEventListener('onSearchStart', function(word, type) {
searchType = type.replace(/^.*\./, '');
$searchInput.val(word);
window.setTimeout(function() { clearButton.refresh(); }, 100);
});
initAutoComplete($searchInput);
$closeExplorer.find('a').on('click', function() {
WatchController.closeSearch();
});
// メニュー拡張
var
detachMenuItems = function() {
var videoExplorerMenu = WatchItLater.videoExplorerMenu;
videoExplorerMenu.myShortcuts .detach();
videoExplorerMenu.videoRanking.detach();
videoExplorerMenu.favTags     .detach();
videoExplorerMenu.favMylists  .detach();
$inputForm.detach();
$closeExplorer.detach();
},
attachMenuItems = function() {
var videoExplorerMenu = WatchItLater.videoExplorerMenu;
if (conf.enableFavTags   ) { videoExplorerMenu.favTags.attach(); }
if (conf.enableFavMylists) { videoExplorerMenu.favMylists.attach(); }
videoExplorerMenu.videoRanking.attach();
videoExplorerMenu.myShortcuts.attach();
$('.videoExplorerMenu')
.find('.itemList>li:first').append($inputForm)
.end().find('.errorMessage').after($closeExplorer);
};
controller._refreshMenu_org = controller._refreshMenu;
controller._refreshMenu = $.proxy(function() {
detachMenuItems();
EventDispatcher.dispatch('beforeRefreshVideoExplorerMenu');
this._refreshMenu_org();
EventDispatcher.dispatch('afterRefreshVideoExplorerMenu');
attachMenuItems();
}, controller);
controller.showDeflist_org         = controller.showDeflist;
controller.showMylist_org          = controller.showMylist;
controller.showOtherUserVideos_org = controller.showOtherUserVideos;
controller.showOwnerVideo_org      = controller.showOwnerVideo;
controller.searchVideo_org         = controller.searchVideo;
controller.showDeflist = $.proxy(function() {
if (conf.disableVideoExplorer && !WatchController.isSearchMode()) {
location.href = "/my/mylist";
return;
}
this.showDeflist_org();
}, controller);
controller.showMylist = $.proxy(function(id) {
if (conf.disableVideoExplorer && !WatchController.isSearchMode()) {
location.href = "/mylist/" + id;
return;
}
this.showMylist_org(id);
}, controller);
controller.showOtherUserVideos = $.proxy(function(id, name) {
if (conf.disableVideoExplorer && !WatchController.isSearchMode()) {
location.href = "/user/" + id;
return;
}
this.showOtherUserVideos_org(id, name);
}, controller);
controller.showOwnerVideo = $.proxy(function() {
if (conf.disableVideoExplorer && !WatchController.isSearchMode()) {
location.href = "/user/" + WatchController.getOwnerId();
return;
}
this.showOwnerVideo_org();
}, controller);
controller.searchVideo = $.proxy(function(word, type) {
if (conf.disableVideoExplorer && !WatchController.isSearchMode()) {
var sortOrder = '?sort=' + conf.searchSortType + '&order=' + conf.searchSortOrder;
location.href = (type === 'tag' ? 'tag' : 'search') + "/" + encodeURIComponent(word) + sortOrder;
return;
}
this.searchVideo_org(word, type);
}, controller);
EventDispatcher.addEventListener('onBottomContentTabViewReset', function(name) {
if (name === 'outline') {
WatchController.closeSearch();
}
});
EventDispatcher.addEventListener('on.config.enableFavTags',
function() { if (WatchController.isSearchMode()) { controller._refreshMenu(); }});
EventDispatcher.addEventListener('on.config.enableFavMylists',
function() { if (WatchController.isSearchMode()) { controller._refreshMenu(); }});
EventDispatcher.addEventListener('onVideoExplorerOpened', function(content) {
setTimeout(function() {
if (conf.videoExplorerHack) {
var pv = require('watchapp/init/PlayerInitializer').rightSidePanelViewController.getPlayerPanelTabsView();
var cpv = pv._commentPanelView;
cpv.resize();
playerConnector.updatePlayerConfig({playerViewSize: ''}); // ノーマル画面モード
}
}, 100);
clearButton.refresh();
$('body').removeClass('videoExplorerOpening');
$('.videoExplorerMenu').addClass('initialized');
});
EventDispatcher.addEventListener('onVideoExplorerRefreshEnd', function(content) {
if (content.getType() === ContentType.USER_VIDEO) {
var items = content.getItems();
if (items.length === 1 && items[0].getContentItemType() !== ContentItemType.VIDEO) {
// ユーザーの投稿動画一覧が公開マイリスト一つだけだったら自動でそれを開く
items[0].stepIn();
return;
}
}
});
EventDispatcher.addEventListener('onVideoExplorerRefreshStart', function(content) {
WindowUtil.scrollFit('#videoExplorer');
});
EventDispatcher.addEventListener('onVideoExplorerOpening', function(content) {
$('body').addClass('videoExplorerOpening');
adjustVideoExplorerSize(true);
});
EventDispatcher.addEventListener('onVideoExplorerClosing', function(content) {
});
EventDispatcher.addEventListener('onBeforeVideoExplorerMenuClear', function() {
detachMenuItems();
});
EventDispatcher.addEventListener('onUpdateSettingPanelVisible', function(isVisible, panel) {
if (isVisible && WatchController.isSearchMode()) {
setTimeout(function() {
WatchController.closeSearch();
setTimeout(function() {
playerConnector.updateSettingsPanelVisible(true, panel);
}, 800);
}, 100);
}
});
EventDispatcher.addEventListener('onFirstVideoExplorerOpened', function() {
window.console.time('onFirstVideoExplorerOpen');
EventDispatcher.addEventListener('onWindowResizeEnd',  adjustVideoExplorerSize);
EventDispatcher.addEventListener('onVideoInitialized', adjustVideoExplorerSize);
adjustVideoExplorerSize(true);
window.console.timeEnd('onFirstVideoExplorerOpen');
});
var duration_match = /^([0-9]+):([0-9]+)/;
controller._item2playlistItem = function (item) {
// 動画長が入るようにする
var length_seconds = 0, len = item.getLength ? item.getLength() : '', m;
if (typeof len === 'string' && (m = duration_match.exec(len)) !== null) {
length_seconds = m[1] * 60 + m[2] * 1;
}
var PlaylistItem = require('watchapp/model/playlist/PlaylistItem');
return new PlaylistItem({
id            : item.getId(),
title         : item.getTitle(),
thumbnail_url : item.getThumbnailUrl(),
view_counter  : item.getViewCounter(),
num_res       : item.getNumRes(),
mylist_counter: item.getMylistCounter(),
mylist_comment: item.getMylistComment(),
first_retrieve: item.getFirstRetrieve(),
ads_counter   : item.getUadCounter(),
length_seconds: length_seconds
});
};
initVideoExplorerItemContent();
$('#playerAlignmentArea').append($toggleCommentPanel);
$toggleCommentPanel.on('click', function() {
AnchorHoverPopup.hidePopup();
$('#playerTabWrapper').toggleClass('w_active');
$toggleCommentPanel.toggleClass('w_active', $('#playerTabWrapper').hasClass('w_active'));
setTimeout(function() {
var pv = require('watchapp/init/PlayerInitializer').rightSidePanelViewController.getPlayerPanelTabsView();
var cpv = pv._commentPanelView;
cpv.resize();
}, 1000);
}).on('mouseover', function() {
AnchorHoverPopup.hidePopup();
});
var toggleVideoExplorerHack = function(v) {
$('#videoExplorer, #content, #footer, #bottomContentTabContainer').toggleClass('w_adjusted', v);
if (v) {
$('#content').append($('.videoExplorerMenu'));
if (WatchController.isSearchMode()) {
playerConnector.updatePlayerConfig({playerViewSize: ''}); // ノーマル画面モード
adjustVideoExplorerSize(true);
}
} else {
$('.videoExplorerContentWrapper').before($('.videoExplorerMenu'));
setTimeout(function() {
if (WatchController.isSearchMode()) {
playerConnector.updatePlayerConfig({playerViewSize: 'small'});
}
}, 1000);
}
};
EventDispatcher.addEventListener('on.config.videoExplorerHack', toggleVideoExplorerHack);
toggleVideoExplorerHack(conf.videoExplorerHack);
watchPageRouter._prepareState_org = watchPageRouter._prepareState;
watchPageRouter._prepareState = $.proxy(function(state) {
if (
conf.videoExplorerHack &&
WatchController.isSearchMode() &&
state.getVideoId() !== this._currentState.getVideoId()
) {
state.prepare({
video: {id: this._watchInfoModel.v}
});
return state;
} else {
return this._prepareState_org(state);
}
}, watchPageRouter);
WatchPageState.prototype.isVideoStateChange = function(state) {
return this.getVideoId() !== state.getVideoId();
};
} // end initVideoExplorer
function initVideoExplorerItemContent() {
// 動画情報表示のテンプレートを拡張
var
overrideItemTemplate = function() {
var VideoExplorerInitializer = require('watchapp/init/VideoExplorerInitializer');
var menu =
'<div class="thumbnailHoverMenu">' +
'<button class="showLargeThumbnail" onclick="WatchItLater.onShowLargeThumbnailClick(this);" title="大きいサムネイルを表示">+</button>' +
'<button class="deleteFromMyMylist" onclick="WatchItLater.onDeleteFromMyMylistClick(this);">マイリスト外す</button>' +
'</div>', $menu = $(menu);
var mylistCommentEditTemplate = [
'<p class="descriptionShort"/>',
'<div class="mylistCommentEdit">',
'<span class="startEditButton" title="マイリストコメントを編集"></span>',
'<textarea class="mylistCommentInput" placeholder="マイリストコメント (改行はShift+ENTER)" />',
'<p class="mylistComment"><pre /></p>',
'</div>',
''].join('');
var $template = $('<div/>').html(VideoExplorerInitializer.videoExplorerView._contentListView._$view.find('.videoItemTemplate').html());
$template.find('.column1 .thumbnailContainer').append($menu).end()
.find('.column4 .balloon').before($menu.clone()).end()
.find('.column4 .balloon').remove().end()
.find('.messageContainer').remove().end()
.find('.lastResBody')
.before($(mylistCommentEditTemplate)).end()
.find('.noImage').remove().end()
.find('.createdTime').after($('<div class="nicorepoOwnerIconContainer"><a target="_blank"><img /></a></div>'));
VideoExplorerInitializer.videoExplorerView._contentListView._$view.find('.videoItemTemplate').html($template.html());
$template = $menu = null;
},
onDeleteFromMyMylistClick = function(elm) {
var VideoExplorerInitializer = require('watchapp/init/VideoExplorerInitializer');
var ContentType = require('watchapp/components/videoexplorer/model/ContentType');
var contentList = VideoExplorerInitializer.videoExplorer.getContentList();
var
$elm       = $(elm),
$item      = $elm.closest('.item'),
$videoItem = $item, //.find(''),//$elm.parent().parent(),
watchId    = $item.attr('data-watch-id'),
ac         = contentList.getActiveContent(),
type       = contentList.getActiveContentType(),
onUpdate   = function(status, r###lt) {
if (status !== "ok") {
Popup.alert('削除に失敗: ' + r###lt.error.description);
} else {
$videoItem.animate({opacity: 0.3}, 500);
}
};
if (type === ContentType.MYLIST_VIDEO) {
if (!ac.getIsMine()) { return; }
Mylist.deleteMylistItem(watchId, ac.getMylistId(), onUpdate, 0);
} else
if (type === ContentType.DEFLIST_VIDEO) {
Mylist.deleteDeflistItem(watchId, onUpdate, 0);
}
},
onShowLargeThumbnailClick = function (elm) {
var $item = $(elm).closest('.item');
var src  = $item.attr('data-thumbnail');
if (!src) { return; }
showLargeThumbnail(src);
};
overrideItemTemplate();
WatchItLater.onDeleteFromMyMylistClick = onDeleteFromMyMylistClick;
WatchItLater.onShowLargeThumbnailClick = onShowLargeThumbnailClick;
// 動画情報表示の拡張
var ItemView = require('watchapp/components/videoexplorer/view/content/item/AbstractVideoContentItemView');
ItemView.prototype._setView_org = ItemView.prototype._setView;
ItemView.prototype._startMylistCommentEdit = function() {
var $edit = this._$item.find('.mylistCommentEdit');
if ($edit.hasClass('edit') || $edit.hasClass('updating')) {
return;
}
$edit.addClass('edit');
var $input = this._$item.find('.mylistCommentInput').off();
var onSubmit = $.proxy(this._onMylistCommentEditSubmit, this);
var onKey = $.proxy(function(e) {
switch (e.keyCode) {
case 13: //ENTER
if (e.shiftKey) { return; }
this._onMylistCommentEditSubmit();
break;
case 27: //ESC
this._onMylistCommentEditCancel();
break;
default:
return;
}
e.stopPropagation();
}, this);
$input
.val(this._item._mylistComment)
.on('blur', onSubmit)
.on('keydown', onKey)
.focus();
};
ItemView.prototype._onMylistCommentEditSubmit = function() {
this._endMylistCommentEdit();
};
ItemView.prototype._onMylistCommentEditCancel = function() {
var $input = this._$item.find('.mylistCommentInput');
$input.val(this._item._mylistComment);
this._endMylistCommentEdit();
};
ItemView.prototype._endMylistCommentEdit = function() {
var item = this._item, $item = this._$item;
var $edit = $item.find('.mylistCommentEdit').removeClass('edit');
var $input = $item.find('.mylistCommentInput').off();
var newComment = $input.val();
if (newComment !== item._mylistComment) {
var VideoExplorerInitializer = require('watchapp/init/VideoExplorerInitializer');
var ContentType = require('watchapp/components/videoexplorer/model/ContentType');
var contentList = VideoExplorerInitializer.videoExplorer.getContentList();
var ac   = contentList.getActiveContent();
var type = contentList.getActiveContentType();
var watchId = item.getId();
var groupId = ac.getMylistId ? ac.getMylistId() : 'deflist';
$edit.addClass('updating');
var onUpdate = function(r###lt) {
console.log(
'%cmylistComment changed!!! watchId: %s groupId: %s comment: 「%s」',
'background: cyan;',
watchId,
groupId,
newComment,
r###lt
);
r###lt = r###lt.toLowerCase();
if (r###lt === 'ok') {
var $newComment = $('<pre/>').text(newComment);
$item.find('.mylistComment').empty().append($newComment);
item._mylistComment = newComment;
} else {
console.log('update fail!!! 「%s」「%s」', r###lt, 'ok', r###lt === 'ok');
Popup.alert('マイリストコメントの編集に失敗 r###lt: ' + r###lt);
}
$edit.removeClass('updating');
if (type === ContentType.MYLIST_VIDEO) {
WatchController.clearMylistCache(groupId);
} else {
WatchController.clearDeflistCache();
}
};
// TODO: clear cache
if (type === ContentType.MYLIST_VIDEO) {
if (!ac.getIsMine()) { return; }
Mylist.updateMylistItem(watchId, groupId, onUpdate, newComment);
} else
if (type === ContentType.DEFLIST_VIDEO) {
Mylist.updateDeflistItem(watchId, onUpdate, newComment);
}
}
};
ItemView.prototype.update_org = ItemView.prototype.update;
ItemView.prototype.update = function() {
// 動画情報表示をゴリゴリいじる場所
var item = this._item, $item = this._$item;
this.update_org(item);
this._$item.find('.deleteFromMyMylist').data('watchId', this._item.getId());
if (item._mylistComment) { // マイリストコメント
$item.find('.mylistComment').css({display: 'block'});
} else {
//$item.find('.mylistComment').remove();
}
// マイリストコメント編集
var startEdit =
this._startMylistCommentEditProxy ?
this._startMylistCommentEditProxy : $.proxy(this._startMylistCommentEdit, this);
this._startMylistCommentEditProxy = startEdit;
$item.find('.startEditButton').on('click', startEdit);
var lastResBody = item.getLastResBody();
if (lastResBody.length > 0) {
this._$lastResBody.css('cssText', 'display: block !important').text(lastResBody);
} else {
this._$lastResBody.remove();
}
var thumbnail = this._$thumbnail.attr('src').replace('.jpg.M', '');
if (item.isMiddleThumbnail()) {
this._$item.find('.thumbnailContainer')
.css('background-image', 'url(' + thumbnail + ')');
this._$thumbnail.remove();
} else {
this._$item
.addClass('smallThumbnail')
.find('.thumbnailContainer')
.css('background-image', 'url(' + thumbnail + ')');
}
$item.attr({
'data-thumbnail': thumbnail,
'data-watch-id': item.getId()
});
if (item._seed && item._seed._info) {
var info = item._seed._info;
if (info.nicorepo_owner) { // ニコレポ
$item.addClass(info.nicorepo_className).addClass('nicorepoR###lt');
var owner = info.nicorepo_owner;
var $iconContainer = $item.find('.nicorepoOwnerIconContainer'), $icon = $iconContainer.find('img'), $link = $iconContainer.find('a');
$icon.attr('src', owner.icon);
$link.attr({'href': owner.page, 'data-ownerid': owner.id, 'title': owner.name + ' さん'});
if (info.nicorepo_className.indexOf('log-user-') >= 0) {
$link.attr(
'onclick',
'if (arguments[0].button > 0) return; arguments[0].preventDefault();' +
'require("watchapp/init/VideoExplorerInitializer").videoExplorerController.showOtherUserVideos(this.dataset.ownerid, this.title);' +
'require("watchapp/util/WindowUtil").scrollFit($("#videoExplorer"));'
);
}
if (info.nicorepo_log.length > 1) {
$item.find('.descriptionShort').html(info.nicorepo_log.join('<br>'));
}
// ニコレポは再生数が取れないので-で埋める
this._$viewCount   .html('-');
this._$commentCount.html('-');
this._$mylistCount .html('-');
$iconContainer = $icon = $link = null;
}
}
if (item._seed && typeof item._seed.description_full === 'string' && item._seed.description_full.length > 150) {
this._$descriptionShort.attr('title', item._seed.description_full);
}
$item = null;
};
ItemView = null;
} // end initVideoExplorerItemContent
var lastVideoOwnerJson = '';
function onWatchInfoReset(watchInfoModel) {
$('body').toggleClass('w_channel', watchInfoModel.isChannelVideo());
EventDispatcher.dispatch('onWatchInfoReset', watchInfoModel);
var owner = WatchController.getOwnerInfo(), owner_json = JSON.stringify(owner);
if (lastVideoOwnerJson.length > 0 && lastVideoOwnerJson !== owner_json) {
EventDispatcher.dispatch('onVideoOwnerChanged', owner);
}
lastVideoOwnerJson = owner_json;
}
function onScreenModeChange(sc) {
setTimeout(function() {
EventDispatcher.dispatch('onScreenModeChange', sc);
}, 500);
}
function initMylistPanel($, conf, w) {
var iframe = Mylist.getPanel('');
iframe.id = "mylist_add_frame";
iframe.className += " fixed";
w.document.body.appendChild(iframe);
iframe.hide(); // ページの初期化が終わるまでは表示しない
var $iframe = $(iframe);
$iframe.find('.mylistSelect').attr('accesskey', ':');
var toggleMylistMenuInFull = function(v) {
$('.mylistPopupPanel')
.toggleClass('hideInFull',    v === 'hide')
.toggleClass('hideAllInFull', v === 'hideAll');
};
EventDispatcher.addEventListener('on.config.hideMenuInFull', toggleMylistMenuInFull);
toggleMylistMenuInFull(conf.hideMenuInFull);
var setMylistPanelPosition = function(v) {
$iframe
.toggleClass('left', v.indexOf('left') >= 0)
.toggleClass('top',  v.indexOf('top')  >= 0);
setTimeout(function() {
$('#yukkuriPanel')
.toggleClass('mylistPanelLeft', v.indexOf('left') >= 0 && v.indexOf('top') < 0);
}, 500);
};
EventDispatcher.addEventListener('on.config.mylistPanelPosition', setMylistPanelPosition);
if (conf.mylistPanelPosition !== '') setMylistPanelPosition(conf.mylistPanelPosition);
var $footer = $('#footer'), $window = $(window);
var toggleMylistPanelStyle = function() {
if ($footer.is(':visible')) {
$iframe.toggleClass('black', $window.scrollTop() + $window.innerHeight() - $footer.offset().top >= 0);
} else {
$iframe.removeClass('black');
}
};
EventDispatcher.addEventListener('onVideoInitialized', function(isFirst) {
toggleMylistPanelStyle();
var newVideoId = watchInfoModel.id;
var newWatchId = watchInfoModel.v;
iframe.watchId(newVideoId, newWatchId);
if (isFirst) iframe.show();
});
EventDispatcher.addEventListener('onScrollEnd',        toggleMylistPanelStyle);
EventDispatcher.addEventListener('onWindowResizeEnd',  toggleMylistPanelStyle);
EventDispatcher.addEventListener('onScreenModeChange', toggleMylistPanelStyle);
EventDispatcher.addEventListener('on.config.hidePlaylist', toggleMylistPanelStyle);
EventDispatcher.addEventListener('on.config.bottomContentsVisibility', toggleMylistPanelStyle);
} //
function initScreenMode() {
var PlayerInitializer = require('watchapp/init/PlayerInitializer');
var PlaylistInitializer = require('watchapp/init/PlaylistInitializer');
EventDispatcher.addEventListener('onVideoInitialized', function(isFirst) {
if (conf.autoBrowserFull) {
setTimeout(function() {
if ($('body').hasClass('up_marquee') && conf.disableAutoBrowserFullIfNicowari) {
// ユーザーニコ割があるときは自動全画面にしない
return;
}
if (WatchController.isSearchMode()) { // TODO: localStorageに直接アクセスすんな
var settingSize = (localStorage["PLAYER_SETTINGS.LAST_PLAYER_SIZE"] === '"normal"') ? 'normal' : 'medium';
WatchController.changeScreenMode(settingSize);
}
WatchController.changeScreenMode('browserFull');
onWindowResizeEnd(); // TODO:;;;;
}, 100);
} else {
if (conf.autoOpenSearch && !WatchController.isSearchMode() && !$('body').hasClass('full_with_browser')) {
WatchController.openSearch();
}
if (conf.autoScrollToPlayer) {
// 初回のみ、プレイヤーが画面内に#まっていてもタグの位置まで自動スクロールさせる。(ファーストビューを固定するため)
// 二回目以降は説明文や検索結果からの遷移なので、必要最小限の動きにとどめる
if (!WatchController.isSearchMode() || isFirst) {
WatchController.scrollToVideoPlayer(isFirst);
}
}
}
});
var lastPlayerConfig = null, lastScreenMode = '';
var restoreVisibility = function() {
$('body').removeClass('hideCommentInput');
};
var togglePlaylist = function(v) {
v = (typeof v === 'boolean') ? v : !$('body').hasClass('fullWithPlaylist');
$('body').toggleClass('fullWithPlaylist', v);
if (v) {
PlaylistInitializer.playlistView.resetView();
}
return v;
};
var toggleMonitorFull = function(v) {
var now = Util.FullScreen.now();
if (now || v === false) {
Util.FullScreen.cancel();
} else if (!now || v === true) {
Util.FullScreen.request(document.body);
}
};
var initShield = function() {
var shield = $('<div id="fullScreenMenuContainer" />');
shield.click(function(e) {
e.stopPropagation();
togglePlaylist();
});
$('#external_nicoplayer').after(shield);
shield = null;
};
initShield();
EventDispatcher.addEventListener('onScreenModeChange', function(sc) {
var mode = sc.mode;
$('body').removeClass('w_fullScreenMenu');
if (mode === 'browserFull' && lastScreenMode !== mode) {
updateFullscreenMenu();
$('body').toggleClass('hideCommentInput', conf.controllerVisibilityInFull === 'hidden');
} else
if (lastScreenMode === 'browserFull' && mode !== 'browserFull') {
$('#playerContainerSlideArea').css({height: ''}); // wall bug fix
restoreVisibility();
toggleMonitorFull(false);
}
lastScreenMode = mode;
});
var onFullscreenWheel = _.debounce(function(direction) {
var fullscreenMenuLevel = conf.fullscreenMenuLevel || 0;
if (direction === 'up') {
fullscreenMenuLevel--;
} else {
fullscreenMenuLevel++;
}
fullscreenMenuLevel = Math.max(-1, Math.min(1, fullscreenMenuLevel));
conf.setValue('fullscreenMenuLevel', fullscreenMenuLevel);
updateFullscreenMenu(fullscreenMenuLevel);
}, 500);
EventDispatcher.addEventListener('onFullscreenWheel', onFullscreenWheel);
var updateFullscreenMenu = function(fullscreenMenuLevel) {
fullscreenMenuLevel =
(typeof fullscreenMenuLevel === 'number') ?
fullscreenMenuLevel : conf.getValue('fullscreenMenuLevel');
var $body = $('body');
if (fullscreenMenuLevel === 0) {
$body.removeClass('w_fullScreenMenu').removeClass('w_hideControlPanel');
} else if (fullscreenMenuLevel < 0) {
$body.removeClass('w_fullScreenMenu').addClass('w_hideControlPanel');
} else if (fullscreenMenuLevel > 0) {
$body.addClass('w_fullScreenMenu').removeClass('w_hideControlPanel');
}
};
var wheelCounter = 0, wheelTimer = null;
EventDispatcher.addEventListener('onWheelNoButton', function(e, delta) {
if (!conf.enableFullScreenMenu) return;
if ((e.target.tagName !== 'OBJECT' && e.target.tagName !== 'HTML') ||
!WatchController.isFullScreen()) return;
if (wheelTimer) {
wheelCounter += delta;
} else {
wheelCounter = 0;
wheelTimer = setTimeout(function() {//
wheelTimer = null;
if (Math.abs(wheelCounter) > 3) {
EventDispatcher.dispatch('onFullscreenWheel',
wheelCounter < 0 ? 'down' : 'up'
);
AnchorHoverPopup.hidePopup();
}
}, 500);
}
});
TouchEventDispatcher.onflick(function(e) {
if (!conf.enableFullScreenMenu) return;
if ((e.direction !=='up' && e.direction !=='down') || e.startEvent.target.tagName !== 'OBJECT' || !WatchController.isFullScreen()) return;
if (wheelTimer) {
clearTimeout(wheelTimer);
wheelTimer = null;
}
EventDispatcher.dispatch('onFullscreenWheel',
e.direction === 'down' ? 'down' : 'up'
);
AnchorHoverPopup.hidePopup();
});
var $fullScreenMenuContainer = $('<div id="fullScreenMenuContainer"/>');
var $fullScreenMenuButtons = $([
'<button class="fullScreenModeSwitch button" data-button-type="playlist">',
'<span class="modeStatus playlistOpening">▼</span>',
'<span class="modeStatus playlistClosing">▲</span>',
'</button>',
'<button class="button prevNext" data-button-type="prev" title="前の動画">≪</button>',
'<button class="button prevNext" data-button-type="next" title="次の動画">≫</button>',
'<button class="stageVideoSwitch button" data-button-type="stagevideo" ',
'title="ハードウェアアクセラレーションのON/OFF"',
'>',
'アクセラレーション: ',
'<span class="modeStatus mode_off">OFF</span>',
'<span class="modeStatus mode_on">ON</span>',
'</button>',
'<button class="toggleMonitorFull button" data-button-type="monitorFull">',
'<span class="monitorFull">モニター全画面</span>',
'</button>',
'<button class="toggleSetting button" data-button-type="setting">',
'⛭設定',
'</button>',
''].join(''));
var onFullScreenMenuContainerClick = function(e) {
var type = $(e.target).attr('data-button-type');
if (type === 'playlist') {
togglePlaylist();
} else if (type === 'stagevideo') {
WatchController.toggleStageVideo();
} else if (type === 'setting') {
ConfigPanel.toggle();
} else if (type === 'monitorFull') {
toggleMonitorFull();
} else if (type === 'prev') {
WatchController.prevVideo();
} else if (type === 'next') {
WatchController.nextVideo();
}
};
$fullScreenMenuContainer
.on('click', onFullScreenMenuContainerClick)
.append($fullScreenMenuButtons);
$('#nicoplayerContainerInner').append($fullScreenMenuContainer);
} // end initScreenMode()
function initPlaylist($, conf, w) {
var
PlaylistInitializer = require('watchapp/init/PlaylistInitializer'),
PlaylistManager     = require('watchapp/view/playlist/PlaylistManager'),
playlist = PlaylistInitializer.playlist,
playlistView = PlaylistInitializer.playlistView,
blankVideoId = 'sm20353707',
blankVideoUrl = 'http://www.nicovideo.jp/watch/' + blankVideoId + '?',
redirectPageUrl = 'http://www.nicovideo.jp/stamp',
items = {},
toCenter = function() { // 表示位置調整
var
pv = PlaylistInitializer.playlistView,
pl = playlist,
current = pl.getPlayingIndex(),
cols = Math.floor($('#playlistContainerInner').innerWidth() / PlaylistManager.getItemWidth()),
center = Math.round(cols / 2);
if (cols < 1) { return; }
var currentLeft = PlaylistManager.getLeftSideIndex();
pv.scroll(Math.max(0, current - center + 1));
},
scroll = function(d) {
var isEffectEnabled = playlistView.isEffectEnabled;
var left = PlaylistManager.getLeftSideIndex();
playlistView.isEffectEnabled = false;
playlistView.scroll(Math.max(0, left + d));
playlistView.isEffectEnabled = isEffectEnabled;
};
playlist.isAutoPlay      = playlist.isContinuous; // 互換用
playlist.enableAutoPlay  = playlist.enableContinuous;
playlist.disableAutoPlay = playlist.disableContinuous;
$('#playlist').find('.playlistInformation').on('dblclick.watchItLater', function(e) {
e.preventDefault();
e.stopPropagation();
toCenter();
});
EventDispatcher.addEventListener('onVideoInitialized', function() {
var pm = PlaylistManager, pv = playlistView, pl = playlist;
var current = pl.getPlayingIndex(), cols = Math.floor($('#playlistContainerInner').innerWidth() / pm.getItemWidth()), center = Math.floor(cols / 2);
if (pm.getLeftSideIndex() + cols <= pl.getNextPlayingIndex()) { toCenter(); }
});
$('#playlistContainer .prevArrow, #playlistContainer .nextArrow').on('mousewheel.watchItLater', function(e, delta) {
if (WatchController.isFullScreen()) { return; }
e.preventDefault();
e.stopPropagation();
scroll(delta *-1);
}).attr('title', 'ホイールで左右にスクロール');
// フルスクリーン中はプレイリストのどこでもスクロールできたほうがいいね
$('#playlist').on('mousewheel.watchItLater', function(e, delta) {
if (WatchController.isFullScreen() || WatchController.isSearchMode() || $('#footer').hasClass('noBottom')) {
e.preventDefault();
e.stopPropagation();
scroll(delta *-1);
}
});
EventDispatcher.addEventListener('onWheelAndButton', function(e, delta, button) {
if (WatchController.isFullScreen()) { return; }
if ($('#playlist').hasClass('dragging')) {
e.preventDefault();
scroll(delta *-1);
}
});
var
updatePos = function() {
if (
conf.hashPlaylistMode === 2 || (conf.hashPlaylistMode === 1 && WatchController.isPlaylistActive())) {
LocationHashParser.setValue('playlist', exportPlaylist());
LocationHashParser.updateHash();
}
if (conf.storagePlaylistMode === 'sessionStorage' || conf.storagePlaylistMode === 'localStorage') {
setTimeout(function() {
w[conf.storagePlaylistMode].setItem('watchItLater_playlist', JSON.stringify(exportPlaylist()));
}, 0);
}
var pos = Math.max((playlist.getPlayingIndex() + 1), 1) + '/' + Math.max(playlist.getItems().length, 1);
$('.generationMessage').text(pos + " - \n" + $('.generationMessage').text().replace(/^.*\n/, ''));
},
resetView = function() {
playlistView.resetView();
},
exportPlaylist = function(option, type, continuous, shuffle) {
var
items = playlist.currentItems,
list = [],
current = 0,
len = conf.debugMode ? Math.min(900, items.length) : Math.min(600, items.length);
for (var i = 0; i < len; i++) {
var item = items[i];
if (item._isPlaying) current = i;
list.push([
item.id,
parseInt(item.mylistCounter, 10).toString(36),
parseInt(item.viewCounter,   10).toString(36),
parseInt(item.numRes,        10).toString(36),
(item.thumbnailUrl ? parseInt(item.thumbnailUrl.split('?i=')[1], 10).toString(36) : 'c490r'),
].join(',') + ':' + item.title
);
}
return {
a: (typeof continuous === 'boolean') ? continuous : WatchController.isPlaylistContinuous(),
r: (typeof shuffle    === 'boolean') ? shuffle    : WatchController.isPlaylistRandom(),
o: option    || playlist.option,
t: type      || playlist.type,
i: list,
c: current
};
},
importPlaylist = function(list) {
var PlaylistItem = require('watchapp/model/playlist/PlaylistItem'), newItems = [], uniq = {}, currentIndex = -1;
WatchController.clearPlaylist();
var currentItem = playlist.currentItems[0];
if (!currentItem) {
var wm = watchInfoModel;
currentItem = new PlaylistItem({
id:             wm.v,
title:          wm.title,
mylist_counter: wm.mylistCount,
view_counter:   wm.viewCount,
num_res:        wm.commentCount,
thumbnail_url:  wm.thumbnail,
first_retrieve: wm.postedAt
});
}
for (var i = 0, len = list.i.length; i < len; i++) {
var
dat = list.i[i],
c = dat.split(':')[0].split(','),
title = dat.replace(/^.*:/, ''),
id = c[0],
thumbnailId = parseInt(c[4], 36);
if (uniq[id] || typeof id !== 'string') { continue; }
uniq[id] = true;
if (id === watchInfoModel.v) {
currentIndex = i;
newItems.push(currentItem);
} else {
var item = new PlaylistItem({
id:             id,
title:          title.replace('<', '&lt;').replace('>', '&gt;'), // ないはずだけど一応
mylist_counter: parseInt(c[1], 36),
view_counter:   parseInt(c[2], 36),
num_res:        parseInt(c[3], 36),
thumbnail_url:  'http://tn-skr' + ((thumbnailId % 4) + 1) + '.smilevideo.jp/smile?i=' + thumbnailId,
first_retrieve: null
});
newItems.push(item);
}
}
// 復元するリストの中に現在の動画がなかった
if (currentIndex === -1) {
if (typeof list.c === 'number') {
if (list.c < newItems.length) {
currentIndex = list.c + 1;
newItems.splice(currentIndex, 0, currentItem);
} else {
currentIndex = list.length;
newItems.push(currentItem);
}
} else {
newItems.unshift(currentItem);
currentIndex = 0;
}
}
var isAutoPlay = playlist.isContinuous();//isAutoPlay();
playlist.reset(newItems, 'WatchItLater', list.t, list.o);
if (!isAutoPlay) { // 本家側の更新でリセット時に勝手に自動再生がONになるようになったので、リセット前の状態を復元する
playlist.disableContinuous();
}
if (currentIndex >= 0) { playlist.playingItem = newItems[currentIndex]; }
if (list.a) { playlist.enableContinuous(); }
if (list.r) {
if (watchInfoModel.id === blankVideoId) {
setTimeout(function() {
WatchController.shufflePlaylist();
}, 3000);
} else {
playlist.enableContinuous();
}
}
},
$dialog = null, $savelink = null, $continuous, $shuffle,
openSaveDialog = function() {
function resetLink() {
var playlist = exportPlaylist(null, null, $continuous.is(':checked'), $shuffle.is(':checked'));
playlist.o = playlist.o || [];
playlist.o.name = $savelink.text();
playlist.t = 'mylist';
LocationHashParser.setValue('playlist', playlist);
if (!playlist.r) {
LocationHashParser.setValue('redirectWatchId', watchInfoModel.id);
} else {
LocationHashParser.deleteValue('redirectWatchId');
}
$savelink
//.attr('href', blankVideoUrl + LocationHashParser.getHash().replace(/\?/g, ''))
.attr('href', redirectPageUrl + LocationHashParser.getHash().replace(/\?/g, ''))
.unbind();
}
function closeDialog() {
$dialog.removeClass('show');
}
if (!$dialog) {
$dialog = $('<div id="playlistSaveDialog" />');
$dialog.append($([
'<div class="shadow"></div>',
'<div class="formWindow"><div  class="formWindowInner">',
'<h3>プレイリスト保存用リンク(実験中)</h3>',
'<p class="link"><a target="_blank" class="playlistSaveLink">保存用リンク</a><button class="editButton">編集</button></p>',
'<label><input type="checkbox" class="continuous">開始時に連続再生をONにする</label><br>',
'<label><input type="checkbox" class="shuffle">開始時にリストをシャッフルする</label>',
'<p class="desc">リンクを右クリックしてコピーやブックマークする事で、現在のプレイリストを保存する事ができます。</p>',
'<button class="closeButton">閉じる</button>',
'</div></div>',
''].join('')));
$savelink   = $dialog.find('a').attr('added', 1);
$continuous = $dialog.find('.continuous');
$shuffle    = $dialog.find('.shuffle');
$dialog.find('.shadow').on('click', closeDialog);
$dialog.find('.editButton').on('click', function() {
var newTitle = prompt('タイトルを編集', $savelink.text());
if (newTitle) {
$savelink.text(newTitle);
resetLink();
}
});
$continuous.on('click', resetLink);
$shuffle   .on('click', resetLink);
$dialog.find('.closeButton').on('click', closeDialog);
$('body').append($dialog);
}
$savelink.text(
$('#playlist .generationMessage')
.text()
.replace(/^.*?\n/, '')
.replace(/^.*「/, '')
.replace(/」.*?$/, '')
.replace(/ *- \d{4}-\d\d-\d\d \d\d:\d\d$/, '') +
' - ' + require('watchapp/util/DateFormat').strftime('%Y-%m-%d %H:%M', new Date())
);
$continuous.attr('checked', WatchController.isPlaylistActive());
$shuffle   .attr('checked', WatchController.isPlaylistRandom());
resetLink();
$dialog.addClass('show');
},
PlaylistMenu = (function($, conf, w, playlist) {
var $popup = null, $generationMessage = $('#playlist').find('.generationMessage'), self;
var
enableContinuous = function() {
playlist.enableContinuous();
},
createDom = function() {
$popup = $('<div class="playlistMenuPopup popupMenu"/>')
.addClass('pop')
.toggleClass('w_touch', isTouchActive);
var $ul = $('<ul/>');
$popup.click(function() {
self.hide();
});
var $shuffle = $('<li>シャッフル: 全体</li>').click(function(e) {
WatchController.shufflePlaylist();
enableContinuous();
});
$ul.append($shuffle);
var $shuffleR = $('<li>シャッフル: 右</li>').click(function(e) {
WatchController.shufflePlaylist('right');
enableContinuous();
});
$ul.append($shuffleR);
var $next = $('<li>検索結果を追加: 次に再生</li>').click(function() {
WatchController.appendSearchR###ltToPlaylist('next');
enableContinuous();
});
$ul.append($next);
var $insert = $('<li>検索結果を追加: 末尾</li>').click(function() {
WatchController.appendSearchR###ltToPlaylist();
enableContinuous();
});
$ul.append($insert);
var $clear = $('<li>リストを消去: 全体</li>').click(function() {
WatchController.clearPlaylist();
});
$ul.append($clear);
var $clearLeft = $('<li>リストを消去: 左</li>').click(function() {
WatchController.clearPlaylist('left');
});
$ul.append($clearLeft);
var $clearRight = $('<li>リストを消去: 右</li>').click(function() {
WatchController.clearPlaylist('right');
});
$ul.append($clearRight);
var $saver = $('<li>リストを保存(実験中)</li>').click(function() {
openSaveDialog();
});
$ul.append($saver);
$popup.append($ul);
$('body').append($popup);
},
show = function() {
if ($popup === null) { createDom(); }
var offset = $generationMessage.offset(), $window = $(window) , pageBottom = $window.scrollTop() + $window.innerHeight();
$popup.css({
left: offset.left,
top: Math.min(offset.top + 24, pageBottom - $popup.outerHeight())
}).show();
},
hide = function() {
if ($popup) { $popup.hide(); }
},
toggle = function() {
if ($popup === null || !$popup.is(':visible')) {
show();
} else {
hide();
}
};
$generationMessage.click(function(e) {
e.preventDefault();
self.toggle();
});
$('body').on('click.watchItLater', function(e) {
var tagName = e.target.tagName, className = e.target.className;
if (className !== 'generationMessage') {
self.hide();
}
});
self = {
show: show,
hide: hide,
toggle: toggle
};
return self;
})($, conf, w, playlist);
var hashlist = LocationHashParser.getValue('playlist');
if (hashlist && hashlist.i && hashlist.i.length > 0) {
try {
console.log('restore playlist!!');
importPlaylist(hashlist);
if (conf.hashPlaylistMode < 1) {
LocationHashParser.removeHash();
}
setTimeout(function() { resetView(); } , 3000);
} catch (e) {
console.log(e);
console.trace();
}
} else
if ((conf.storagePlaylistMode === 'sessionStorage' || conf.storagePlaylistMode === 'localStorage') && w[conf.storagePlaylistMode] && !playlist.isContinuous()) {
try {
console.log('restore playlist:' + conf.storagePlaylistMode);
var list = JSON.parse(w[conf.storagePlaylistMode].getItem('watchItLater_playlist'));
if (list !== null) { importPlaylist(list); }
setTimeout(function() { resetView(); } , 3000);
} catch (e) {
console.log('プレイリストの復元に失敗!', e);
}
} else {
updatePos();
}
EventDispatcher.addEventListener('onVideoExplorerOpened', function() {
// 2013/09/26 本家側で開閉を記録するようになった -> 2014/03/03 また記憶しなくなった
// 通常画面でプレイリストを表示にしてるなら、開いた状態をデフォルトにする
if (conf.hidePlaylistInVideoExplorer === false) {
playlist.open();
}
});
$('#playlist .browserFullOption a').on('click', function() {
if (WatchController.isSearchMode()) {
conf.setValue('hidePlaylistInVideoExplorer', !conf.hidePlaylistInVideoExplorer);
}
});
EventDispatcher.addEventListener('on.config.hashPlaylistMode', function(v) {
if (v === 0) {
LocationHashParser.deleteValue('playlist');
LocationHashParser.removeHash();
} else
if (v === 1 || v === 2) {
var msg = [
'【警告】「プレイリストが消えないモード」は実験中の機能です。',
'',
'この機能を使うと、ページをリロードしたりブックマークしてもプレイリストが消えなくなりますが、',
'データを力技で保持するため、ページのURLがものすごく長く(※)なります。',
'',
'そのため、ブラウザのパフォーマンスが低下したり、未知の不具合が発生する可能性があります。',
'それでもこの機能を使ってみたい!という方だけ「OK」を押してください。',
'',
'※ 数千~数万文字くらい!',
''].join('\n');
if (confirm(msg)) {
LocationHashParser.setValue('playlist', exportPlaylist());
LocationHashParser.updateHash();
} else {
conf.setValue('hashPlaylistMode', 0);
ConfigPanel.refresh();
}
}
});
$('#playlist .browserFullOption').on('click.bugfix', resetView);
$('.generationMessage, .prevArrow, .nextArrow, .playbackOption').on('mouseover', function() {
AnchorHoverPopup.hidePopup();
});
playlist.addEventListener('changePlaybackMode', function(mode) {
console.log('changePlaybackMode', mode, conf.hashPlaylistMode);
if (mode === 'normal' && conf.hashPlaylistMode < 2) {
LocationHashParser.removeHash();
} else {
updatePos();
}
});
EventDispatcher.addEventListener('onFirstVideoInitialized', function() {
updatePos();
EventDispatcher.addEventListener('onScreenModeChange', function(sc) {
resetView();
});
EventDispatcher.addEventListener('onWatchInfoReset', function() {
updatePos();
});
playlist.addEventListener('reset', function() {
EventDispatcher.dispatch('onPlaylistReset');
updatePos();
});
playlist.addEventListener('update', function() {
EventDispatcher.dispatch('onPlaylistUpdate');
updatePos();
});
});
var togglePlaylistDisplay = function(v) {
var $playlist = $('#playlist');
if (!v) {
$playlist.addClass('w_show').removeClass('w_closing');
} else {
$playlist.addClass('w_closing');
setTimeout(function() { $playlist.removeClass('w_show');}, 500);
}
};
EventDispatcher.addEventListener('on.config.hidePlaylist', togglePlaylistDisplay);
togglePlaylistDisplay(conf.hidePlaylist);
// プレイリスト消えないモードの時はプレイリストを勝手におすすめに置き換える機能をキャンセル
(function() {
var ld = require('watchapp/init/VideoExplorerInitializer').videoExplorerController._videoExplorerPlaylistResetArgumentsLoader;
ld.load_org = ld.load;
ld.load = $.proxy(function(a, b, c) {
if (conf.storagePlaylistMode !== '') {
return;
}
this.load_org(a, b, c);
}, ld);
ld = null;
})();
} // end initPlaylist
function initPageHeader($, conf, w) {
$('.videoDetailExpand h2').addClass('videoDetailToggleButton');
} // end initPageHeader
function initVideoTagContainer($, conf, w) {
var TagInitializer = require('watchapp/init/TagInitializer');
var $videoHeaderTagEditLinkArea = null, $toggleTagEditText = null, baseTagHeight = 72, currentHeight = 72;
var tagListView = TagInitializer.tagViewController.tagListView, $videoHeader = $('.videoHeaderOuter');
tagListView.getCurrentDefaultHeight_org = tagListView.getCurrentDefaultHeight;
tagListView.getCurrentDefaultHeight = function() {
if ($('body').hasClass('full_with_browser')) {
return tagListView.getCurrentDefaultHeight_org();
}
return currentHeight;
};
$videoHeaderTagEditLinkArea = $('.toggleTagEditInner .videoHeaderTagEditLinkArea');
$('.toggleTagEdit').append($videoHeaderTagEditLinkArea);
$toggleTagEditText = $('<span class="toggleText">' + $('.toggleTagEditInner').text() + '</span>');
$('.toggleTagEditInner').empty().append($toggleTagEditText).append($videoHeaderTagEditLinkArea);
var onTagReset = function() {
try {
// タグが2行以下だったら自動的に狭くする処理
if (!conf.enableAutoTagContainerHeight) { return; }
currentHeight = Math.min(baseTagHeight, $('#videoTagContainer').find('.tagInner').innerHeight());
if (baseTagHeight !== currentHeight) {
var $toggle = $('#videoTagContainer').find('.toggleTagEdit');
$videoHeader.removeClass('tag1Line').removeClass('tag2Lines');
if (currentHeight < 36) { // 1行以下の時
$videoHeader.addClass('tag1Line');
} else {
if (currentHeight <= 60) { // 2行以下の時
$videoHeader.addClass('tag2Lines');
}
}
TagInitializer.tagViewController.tagListView.fit();
} else {
$videoHeader.removeClass('tag1Line').removeClass('tag2Lines');
TagInitializer.tagViewController.tagListView.fit();
}
} catch (e) {
console.log(e);
}
};
EventDispatcher.addEventListener('onFirstVideoInitialized', function() {
EventDispatcher.addEventListener('onVideoInitialized', onTagReset);
});
TagInitializer.tagList.addEventListener('reset', onTagReset);
if (conf.enableAutoTagContainerHeight) {
TagInitializer.tagViewController.tagViewPinStatus.changeStatus(true);
}
window.setTimeout(onTagReset, 1000);
$videoHeaderTagEditLinkArea = $toggleTagEditText = null;
var NicoPlayerConnector = require('watchapp/model/player/NicoPlayerConnector');
NicoPlayerConnector.onTagDataReceived_org = NicoPlayerConnector.onTagDataReceived;
NicoPlayerConnector.onTagDataReceived = function(a) {
if (conf.disableTagReload) {
return;
}
NicoPlayerConnector.onTagDataReceived_org(a);
};
} // end initVideoTagContainer
function initVideoReview($, conf, w) {
var __css__ = Util.here(function() {/*
.sidePanel #videoReview { margin: 0 auto; }
#outline.w_compact #videoReview { width: 300px; }
#outline.w_compact textarea.newVideoReview { width: 277px; }
#outline.w_compact #videoReviewHead { width: 283px; }
#outline.w_compact #videoReview .stream { width: 300px; }
#outline.w_compact #videoReview .inner { width: 300px; }
#outline.w_compact .commentContent { width: 278px; }
#outline.w_compact .commentContentBody { width: 232px; }
.sidePanel.w_review #videoReview { width: 308px; }
.sidePanel.w_review textarea.newVideoReview { width: 286px; }
.sidePanel.w_review #videoReviewHead { width: 291px; }
.sidePanel.w_review #videoReview .stream { width: 308px; }
.sidePanel.w_review #videoReview .inner { width: 308px; }
.sidePanel.w_review .commentContent { width: 286px; }
.sidePanel.w_review .commentContentBody { width: 240px; }
body:not(.full_with_browser) .w_wide .sidePanel.w_review #videoReview { width: 400px; }
body:not(.full_with_browser) .w_wide .sidePanel.w_review textarea.newVideoReview { width: 377px; }
body:not(.full_with_browser) .w_wide .sidePanel.w_review #videoReviewHead { width: 383px; }
body:not(.full_with_browser) .w_wide .sidePanel.w_review #videoReview .stream { width: 400px; }
body:not(.full_with_browser) .w_wide .sidePanel.w_review #videoReview .inner { width: 400px; }
body:not(.full_with_browser) .w_wide .sidePanel.w_review .commentContent { width: 378px; }
body:not(.full_with_browser) .w_wide .sidePanel.w_review .commentContentBody { width: 332px; }
body.videoExplorer .sidePanel.w_review #videoReview { width: 400px; }
body.videoExplorer .sidePanel.w_review textarea.newVideoReview { width: 377px; }
body.videoExplorer .sidePanel.w_review #videoReviewHead { width: 383px; }
body.videoExplorer .sidePanel.w_review #videoReview .stream { width: 400px; }
body.videoExplorer .sidePanel.w_review #videoReview .inner { width: 400px; }
body.videoExplorer .sidePanel.w_review .commentContent { width: 378px; }
body.videoExplorer .sidePanel.w_review .commentContentBody { width: 332px; }
body:not(.videoExplorer) .sidePanel .commentUserProfile, body:not(.videoExplorer) .sidePanel .panelTrigger {
display: none !important;
}
body.videoExplorer .sidePanel .commentUserProfile {
position: fixed;
top:  36px !important;
left: auto !important;
right:  0 !important;
z-index: 11000;
}
.sidePanel .getMoreReviewComment {
margin-bottom: 256px;
}
*/});
var reviewCss = addStyle(__css__, 'videoReviewCss');
/*
EventDispatcher.addEventListener('onFirstVideoInitialized', function() { setTimeout(function() {
var elms = [
'#videoReview',
'textarea.newVideoReview',
'#videoReviewHead',
'#videoReview .stream',
'#videoReview .inner',
'.commentContent',
'.commentContentBody'
];
var css = [], $baseElement = $('#videoReview');
var makeCss = function (targetWidth, preSel) {
var px = targetWidth - $baseElement.outerWidth();
for (var v in elms) {
var $e = $(elms[v]), newWidth = $e.width() + px;
css.push([
preSel, elms[v], ' { width: ', newWidth,'px; }\n'
].join(''));
}
};
makeCss(300, '#outline.w_compact ');
makeCss(308, '.sidePanel.w_review ');
makeCss(400, '.sidePanel.w_review.w_wide ');
makeCss(400, 'body.videoExplorer .sidePanel.w_review ');
console.log(css.join(''));
var reviewCss = addStyle(css.join(''), 'videoReviewCss');
}, 3000);});
*/
} // end initVideoReview
function initNews() {
var TextMarqueeInitializer = require('watchapp/init/TextMarqueeInitializer');
var stopNicoNewsPolling = function() {
TextMarqueeInitializer.textMarqueeItemDispatcher.stop();
TextMarqueeInitializer.textMarqueeItemList.list.length = 0;
};
var toggleNoNews = function() {
$('#content').toggleClass('noNews', conf.hideNicoNews || conf.customPlayerSize !== '');
if ($('#content').hasClass('noNews')) {
stopNicoNewsPolling();
}
};
EventDispatcher.addEventListener('on.config.hideNicoNews',     toggleNoNews);
EventDispatcher.addEventListener('on.config.customPlayerSize', toggleNoNews);
toggleNoNews();
//if (conf.enableNewsHistory) { NicoNews.initialize(w); }
} //
function initEvents() {
var PlayerInitializer = require('watchapp/init/PlayerInitializer');
var VideoExplorerInitializer = require('watchapp/init/VideoExplorerInitializer');
var watchInfoModel    = require('watchapp/model/WatchInfoModel').getInstance();
var pac = PlayerInitializer.playerAreaConnector;
var npc = PlayerInitializer.nicoPlayerConnector;
advice.after(npc, 'onCommentListInitialized', function() {
EventDispatcher.dispatch('onCommentListInitialized');
});
advice.after(npc, 'onVideoInitialized', onVideoInitialized);
advice.after(npc, 'onVideoEnded',   onVideoEnded);
advice.after(npc, 'onVideoStopped', onVideoStopped);
// pac.addEventListener('onSystemMessageFatalErrorSended', onSystemMessageFatalErrorSended);
// WatchInitializer.watchModel.addEventListener('error', function() {console.log(arguments);});
pac.addEventListener('updateSettingsPanelVisible', function(isVisible, panel) {
EventDispatcher.dispatch('onUpdateSettingPanelVisible', isVisible, panel);
});
watchInfoModel.addEventListener('reset', onWatchInfoReset);
watchInfoModel.addEventListener('beforeReset', function() {
window.console.time('watchInfoModelReset');
EventDispatcher.dispatch('onWatchInfoBeforeReset');
});
watchInfoModel.addEventListener('afterReset',  function() {
window.console.timeEnd('watchInfoModelReset');
EventDispatcher.dispatch('onWatchInfoAfterReset');
});
PlayerInitializer.playerScreenMode.addEventListener('change', onScreenModeChange);
var explorer = VideoExplorerInitializer.videoExplorer;
explorer.addEventListener('openStart',    onVideoExplorerOpening);
explorer.addEventListener('openEnd',      onVideoExplorerOpened);
explorer.addEventListener('closeStart',   onVideoExplorerClosing);
explorer.addEventListener('closeEnd',     onVideoExplorerClosed);
explorer.addEventListener('refreshStart', onVideoExplorerRefreshStart);
explorer.addEventListener('refreshEnd',   onVideoExplorerRefreshEnd);
explorer.addEventListener('changeCurrentPage',   onVideoExplorerChangePage); //
$('body').dblclick(function(e){
var tagName = e.target.tagName, cls = e.target.className || '';
if (tagName === 'SELECT' || tagName === 'INPUT' ||  tagName === 'BUTTON' || cls.match(/mylistPopupPanel/)) {
return;
}
if (!WatchController.isFullScreen()) {
AnchorHoverPopup.hidePopup();
if (conf.doubleClickScroll) {
e.preventDefault();
EventDispatcher.dispatch('onScrollReset');
WatchController.scrollToVideoPlayer(true);
}
}
});
var bottomContentTabView = require('watchapp/view/BottomContentTabView').getInstance();
bottomContentTabView.addEventListener('changeContent', function(name) {
EventDispatcher.dispatch('onBottomContentTabViewReset', name);
});
Mylist.onDefMylistUpdate(function() {
//WatchController.clearDeflistCache();
});
Mylist.onMylistUpdate(function(info) {
WatchController.clearMylistCache(info.groupId);
});
$(window).on('beforeunload.watchItLater', function(e) {
conf.setValue('lastCommentVisibility', WatchController.commentVisibility() ? 'visible' : 'hidden');
}).on('resize', window._.debounce(function() {
AnchorHoverPopup.hidePopup();
EventDispatcher.dispatch('onWindowResizeEnd');
}, 1000));
$(document).on('scroll', function() {
if (document.body.style.pointerEvents !== 'none') {
document.body.style.pointerEvents = 'none';
}
});
$(document).on('scroll', window._.debounce(function() {
document.body.style.pointerEvents = '';
EventDispatcher.dispatch('onScrollEnd');
}, 500));
EventDispatcher.addEventListener('onFirstVideoInitialized', function() {
pac.addEventListener('onVideoChangeStatusUpdated', onVideoChangeStatusUpdated);
});
window.addEventListener('message', function(event) {
if (event.origin.indexOf('nicovideo.jp') < 0) return;
try {
var data = JSON.parse(event.data);
if (data.id !== 'WatchItLater') { return; }
EventDispatcher.dispatch('onMessage', data.body, data.type);
} catch (e) {
console.log(
'%cError: window.onMessage - ',
'color: red; background: yellow',
e, event.origin, event.data);
}
});
} //
function initAdditionalButtons() {
var createPlaylistToggle = function() {
var $playlistToggle = $('<button title="プレイリスト表示/非表示" class="playlistToggle">プレイリスト</button>');
$playlistToggle.on('click', function() {
AnchorHoverPopup.hidePopup();
conf.setValue('hidePlaylist', !!!conf.hidePlaylist);
});
var togglePlaylistDisplay = function(v) {
$playlistToggle.toggleClass('w_show', !v);
};
EventDispatcher.addEventListener('on.config.hidePlaylist', togglePlaylistDisplay);
togglePlaylistDisplay(conf.hidePlaylist);
return $playlistToggle;
};
var createOpenExplorer = function() {
return $('<button class="openVideoExplorer">検索▼</button>').on('click', function() {
WatchController.openSearch();
if (!$('body').hasClass('content-fix')) {
WatchController.scrollToVideoPlayer(true);
}
});
};
var $div = $('<div class="bottomAccessContainer"/>').append(createPlaylistToggle()).append(createOpenExplorer());
var $headerMenu = $('<li class="watchItLaterSettingMenu"><a href="javascript:;" title="WatchItLaterの設定">WatchItLater設定</a></li>');
$('#siteHeaderRightMenuFix').after($headerMenu);
$('#outline .outer').before($div);
var $container = $('<div class="bottomConfButtonContainer" />'), $conf = $('<button title="WatchItLaterの設定">設定</button>');
var $explorerConf = $('<button><span class="open">`・ω・´</span><span class="close">´・ω・`</span></button>');
var toggleConf = function(e) {
e.stopPropagation();
AnchorHoverPopup.hidePopup();
ConfigPanel.toggle();
};
$container.append($conf);
$conf.addClass('openConfButton');
$conf.on('click', toggleConf);//.attr('accesskey', 'p');
$('#outline .outer').before($container);
$headerMenu.find('a').on('click', toggleConf);//.attr('accesskey', 'p');
$('.videoExplorerBody').append($explorerConf);
$explorerConf
.on('click',
function() { WatchItLater.config.set('videoExplorerHack', !WatchItLater.config.get('videoExplorerHack')); })
.addClass('videoExplorerConfig');
var $body = $('body'), $window = $(window);
EventDispatcher.addEventListener('onWindowResizeEnd', function() {
if (WatchController.isSearchMode() || WatchController.isFullScreen()) { return; }
var w = $div.outerWidth(), threshold = ($(window).innerWidth() - 960) / 2;
$('#outline').toggleClass('under960', w > threshold && !$('#footer').hasClass('noBottom'));
});
} // end initAdditionalButtons
function initSearchContent($, conf, w) {
var VideoExplorerInitializer = require('watchapp/init/VideoExplorerInitializer');
var ContentType      = require('watchapp/components/videoexplorer/model/ContentType');
var SearchSortOrder  = require('watchapp/components/nicosearchstatus/model/SearchSortOrder');
var SearchType       = require('watchapp/components/nicosearchstatus/model/SearchType');
var View             = require('watchapp/components/videoexplorer/view/content/SearchContentView');
var vec              = VideoExplorerInitializer.videoExplorerController;
var explorer         = vec.getVideoExplorer();
var content          = explorer.getContentList().getContent(ContentType.SEARCH);
var relatedTag       = new NicoSearchRelatedTag({});
var newSearch        = new NewNicoSearch({});
var newSearchWrapper = new NewNicoSearchWrapper({search: newSearch});
var pager            = content._pager;
var __css__          = Util.here(function() {/*
.newSearchOption {
text-align: center; margin-bottom: 16px; padding: 8px;
background: #eee;
display: none;
}
.newSearchOption select, .newSearchOption label{
margin-right: 32px;
}
.newSearchOption .reset{
cursor: pointer; background: #eee;
}
.newSearchOption p{
margin: 8px;
}
.newSearchOption .ownerName {
}
.w_sugoiSearch .newSearchOption {
display: block;
}
.newSearchOption select option{
background: #eef;
}
.newSearchOption select option:nth-child(1) {
background: #fff;
}
.relatedTagList {
}
.relatedTagList p{
display: inline-block; margin: 4px;
}
.relatedTagList li, .relatedTagList ul {
display: inline;
margin: 0 8px 0 0;
list-style: none;
word-break: break-all;
}
.relatedTagList li {
background: #f4f4f4; padding: 2px 4px;
border: solid 1px #999;
border-radius: 4px;
line-height: 180%;
}
.relatedTagList li:hover {
}
.relatedTagList li:hover a{
text-decoration: none;
}
.sugoiOption {
display: none;
}
.w_sugoiSearch .sugoiOption {
display: block; background: #eef;
}
.w_sugoiSearch optgroup.sugoiOption {
font-weight: bolder;
}
*/});
addStyle(__css__, 'searchContent');
// 動画表示のテンプレート拡張
var $template = $('<div/>').html(VideoExplorerInitializer.videoExplorerView._contentListView._$view.find('.searchContentTemplate').html());
$template.find('.searchSortOrder')
.append([
'<optgroup label="新検索専用" class="sugoiOption">',
'<option value="sort=_hot&amp;order=d""    class="sugoiOption">人気が高い順</option>',
'<option value="sort=_popular&amp;order=d" class="sugoiOption">並び順指定なし</option>',
'<option value="sort=_explore&amp;order=d" class="sugoiOption">新着優先</option>',
//             '<option value="sort=_id&amp;order=d" class="sugoiOption">動画ID順</option>',
'</optgroup>'
].join(''));
VideoExplorerInitializer.videoExplorerView._contentListView._$view.find('.searchContentTemplate').html($template.html());
$template = null;
var RelatedTagView = function() { this.initialize.apply(this, arguments); };
RelatedTagView.prototype = {
_$view: null,
_relatedTag: null,
initialize: function(params) {
this._relatedTag = params.relatedTag;
this._$view       = params.$view;
this._$list       = this._$view.find('ul');
},
getView: function() {
return this._$view;
},
detach: function() {
this._$view.detach();
},
update: function(candidates) {
if (!candidates || candidates.length < 1) {
this.detach();
return;
}
if (candidates.length > 10) {
candidates = candidates
.map(function(a){return {weight:Math.random(), value:a};})
.sort(function(a, b){return a.weight - b.weight;})
.map(function(a){return a.value;});
}
var $ul = this._$list.empty();
for (var i = 0, len = Math.min(10, candidates.length); i < len; i++) {
$ul.append(this._create$tag(candidates[i].tag));
}
},
clear: function() {
this._$list.empty();
},
_create$tag: function(text) {
var
$a = $('<a/>')
.html(text)
.attr('href', 'http://search.nicovideo.jp/video/tag/' + encodeURIComponent(text))
.on('click', Util.Closure.openNicoSearch(text)),
$tag = $('<li/>').append($a);
return $tag;
}
};
var NewSearchOptionView = function() { this.initialize.apply(this, arguments); };
NewSearchOptionView.prototype = {
_content: null,
_$view: null,
_$startTimeRange: null,
_$lengthSecondsRange: null,
initialize: function(params) {
this._content             = params.content;
this._$view               = params.$view;
this._$startTimeRange     = this._$view.find('.startTimeRange');
this._$lengthSecondsRange = this._$view.find('.lengthSecondsRange');
this._$musicDlFilter      = this._$view.find('.musicDlFilter');
this._$ownerFilter        = this._$view.find('.ownerFilter');
this._$ownerName        = this._$view.find('.ownerName');
this._$commentCountRange  = this._$view.find('.commentCountRange');
this._$resetButton        = this._$view.find('.reset');
this._$startTimeRange    .val(params.startTimeRange     || '');
this._$lengthSecondsRange.val(params.lengthSecondsRange || '');
this._$commentCountRange .val(params.commentCountRange || '');
this._$musicDlFilter     .attr('checked', !!params.musicDlFilter);
this._$startTimeRange    .on('change', $.proxy(this._onStartTimeRangeSelect    , this));
this._$lengthSecondsRange.on('change', $.proxy(this._onLengthSecondsRangeSelect, this));
this._$commentCountRange .on('change', $.proxy(this._onCommentCountRangeSelect , this));
this._$musicDlFilter     .on('click',  $.proxy(this._onMusicDlFilterChange     , this));
this._$ownerFilter       .on('click',  $.proxy(this._onOwnerFilterChange       , this));
this._$resetButton       .on('click',  $.proxy(this.reset                      , this));
EventDispatcher.addEventListener('onVideoOwnerChanged', $.proxy(this.onVideoOwnerChange, this));
this._$ownerName.text(WatchController.getOwnerName());
},
getView: function() {
return this._$view;
},
detach: function() {
this._$view.detach();
},
update: function() {
},
onVideoOwnerChange: function(ownerInfo) {
this._content.setOwnerFilter(false);
this._$ownerFilter.prop('checked', false);
this._$ownerName.text(ownerInfo.name);
},
_onStartTimeRangeSelect: function() {
this._content.setStartTimeRange(this._$startTimeRange.val());
this.contentRefresh();
},
_onLengthSecondsRangeSelect: function() {
this._content.setLengthSecondsRange(this._$lengthSecondsRange.val());
this.contentRefresh();
},
_onCommentCountRangeSelect: function() {
this._content.setCommentCountRange(this._$commentCountRange.val());
this.contentRefresh();
},
_onMusicDlFilterChange: function() {
this._content.setMusicDlFilter(!!this._$musicDlFilter.prop('checked'));
this.contentRefresh();
},
_onOwnerFilterChange: function() {
this._content.setOwnerFilter(!!this._$ownerFilter.prop('checked'));
this.contentRefresh();
},
contentRefresh: function() {
var params = this._content.getParams();
params.page = 1;
this._content.changeState(params);
this._content.refresh({page: 1});
},
refresh: function() {
//console.log('refresh!', this._content.getOwnerFilter(), this._content.getMusicDlFilter(false));
this._$startTimeRange    .val(this._content.getStartTimeRange('') || '');
this._$lengthSecondsRange.val(this._content.getLengthSecondsRange('') || '');
this._$musicDlFilter     .prop('checked', !!this._content.getMusicDlFilter(false));
this._$ownerFilter       .prop('checked', !!this._content.getOwnerFilter());
},
reset: function() {
var v = this._$startTimeRange.val() + this._$lengthSecondsRange.val();
if (v !== '') {
this._content.setStartTimeRange('');
this._content.setLengthSecondsRange('');
this._content.setMusicDlFilter(false);
this._$startTimeRange.val('');
this._$lengthSecondsRange.val('');
this._$musicDlFilter.prop('checked', false);
this._content.changeState({ page: 1 });
//this._content.refresh({ page: 1 });
}
}
};
var relatedTagView = new RelatedTagView({
relatedTag: relatedTag,
$view: $('<div class="relatedTagList"><p>関連タグ: </p><ul></ul></div>')
});
var newSearchOptionView = new NewSearchOptionView({
content: content,
startTimeRange:     conf.searchStartTimeRange,
lengthSecondsRange: conf.searchLengthSecondsRange,
commentCountRange:  conf.searchCommentCountRange,
musicDlFilter:      conf.searchMusicDlFilter,
$view: $([
'<div class="newSearchOption">',
'<span>投稿日時: </span>',
'<select class="startTimeRange" name="u">',
'<option selected="selected" value=""   >指定なし</option>',
'<option                     value="24h">24時間以内</option>',
'<option                     value="1w" >1週間以内</option>',
'<option                     value="1m" >1ヶ月(30日)以内</option>',
'<option                     value="3m" >3ヶ月(90日)以内</option>',
'<option                     value="6m" >6ヶ月(180日)以内</option>',
'</select>',
'<span>再生時間: </span>',
'<select class="lengthSecondsRange" name="l">',
'<option selected="selected" value=""     >指定なし</option>',
'<option                     value="short">5分以内</option>',
'<option                     value="long" >20分以上</option>',
'</select>',
'<br>',
'<span>コメント数: </span>',
'<select class="commentCountRange" name="commentCount">',
'<option selected="selected" value=""     >指定なし</option>',
'<option                     value="10"   >  10以上</option>',
'<option                     value="100"  > 100以上</option>',
'<option                     value="1000" >1000以上</option>',
'</select>',
'<p>',
'<label>',
'<input type="checkbox" name="m" class="musicDlFilter">音楽DL対応のみ</input>',
'</label>',
'<label>',
'<input type="checkbox" name="owner" class="ownerFilter"><span class="ownerName">この投稿者</span>&nbsp;の動画のみ</input>',
'</label>',
'</p>',
'</div>',
''].join(''))
});
content._originalWord = '';
content.changeState_org = content.changeState;
content.changeState = $.proxy(function(params, callback) {
var word = WatchApp.get(params, 'searchWord', 'string', '');
var type = WatchApp.get(params, 'searchType', 'string', this.getSearchType());
if (typeof word === 'string' && word.length > 0) {
this._originalWord = word;
if (conf.defaultSearchOption && conf.defaultSearchOption !== '') {
if (word.indexOf(conf.defaultSearchOption) < 0 && !word.match(/(sm|nm|so)\d+/)) {
params.searchWord += " " + conf.defaultSearchOption;
}
}
}
AnchorHoverPopup.hidePopup();
EventDispatcher.dispatch('onSearchStart', this._originalWord, type);
this.changeState_org(params, callback);
}, content);
// ニコニコ新検索エンジンを使うための布石
content._searchEngineType     = 'sugoi';//conf.searchEngine;
content._lastSearchEngineType = 'sugoi';//conf.searchEngine;
content.setSearchEngineType   = $.proxy(function(type) {
this._searchEngineType = type;
this.updateSearchPageItemCount();
}, content);
content.updateSearchPageItemCount = $.proxy(function() {
this._pager._pageItemCount = this._searchEngineType === 'sugoi' ? conf.searchPageItemCount : 32;
}, content);
content.getSearchEngineType     = $.proxy(function()   {
return this._searchEngineType === 'sugoi' ? 'sugoi' : 'normal';
}, content);
content.setLastSearchEngineType = $.proxy(function(type) { this._lastSearchEngineType = type; }, content);
content.getLastSearchEngineType = $.proxy(function()     { return this._lastSearchEngineType; }, content);
content._newSearchWrapper     = newSearchWrapper;
content._startTimeRange       = conf.searchStartTimeRange;
content._lengthSecondsRange   = conf.searchLengthSecondsRange;
content._commentCountRange    = conf.searchCommentCountRange;
content._musicDlFilter        = conf.searchMusicDlFilter;
content._ownerFilter          = false;
content.getStartTimeRange     = $.proxy(function() { return this._startTimeRange;           }, content);
content.getLengthSecondsRange = $.proxy(function() { return this._lengthSecondsRange;       }, content);
content.getCommentCountRange  = $.proxy(function() { return this._commentCountRange;        }, content);
content.getMusicDlFilter      = $.proxy(function() { return this._musicDlFilter;            }, content);
content.getOwnerFilter        = $.proxy(function() { return this._ownerFilter;              }, content);
content.setStartTimeRange     = $.proxy(function(value) {
this._startTimeRange = value;
conf.setValue('searchStartTimeRange', value);
}, content);
content.setLengthSecondsRange = $.proxy(function(value) {
this._lengthSecondsRange = value;
conf.setValue('searchLengthSecondsRange',value);
}, content);
content.setCommentCountRange = $.proxy(function(value) {
this._commentCountRange = value;
conf.setValue('searchCommentCountRange',value);
}, content);
content.setMusicDlFilter      = $.proxy(function(value) {
this._musicDlFilter = !!value;
conf.setValue('searchMusicDlFilter', !!value);
}, content);
content.setOwnerFilter        = $.proxy(function(value) {
this._ownerFilter = !!value;
}, content);
// 新検索独自のソート順への対応
var _searchSortOrder =
content._nicoSearchStatus ?
content._nicoSearchStatus._searchSortOrder : content._searchSortOrder;
advice.around(_searchSortOrder, '_flush', function(_flush, type) {
var sort = this._sort[SearchType.KEYWORD];
if (sort === '_hot' || sort === '_popular'  || sort === '_explore' || sort === '_id') { // 新検索にしかないパラメータは保存しない
return;
}
_flush.call(this, type);
});
EventDispatcher.addEventListener('on.config.searchPageItemCount', function() {
content.updateSearchPageItemCount();
});
//content.getParams_org = content.getParams;
advice.around(content, 'getParams', function(getParams) {
var params = getParams.call(this);
params = $.extend(true, {
l:    this.getLengthSecondsRange(),
u:    this.getStartTimeRange(),
m:    this.getMusicDlFilter(),
size: this._pager._pageItemCount,
commentCount: this.getCommentCountRange()
}, params);
if (this.getOwnerFilter()) {
if (WatchController.isChannelVideo()) {
params.channelId = WatchController.getOwnerId();
} else {
params.userId = WatchController.getOwnerId();
}
}
return params;
});
// タグ検索だけ毎回ソート順がデフォルトにリセットされるようになったので、
// デフォルト値を書き換えるという力技で対抗
SearchSortOrder.TAG_DEFAULT_SORT  = conf.searchSortType;
SearchSortOrder.TAG_DEFAULT_ORDER = conf.searchSortOrder;
_searchSortOrder.getSortFromCookie  = function() { return conf.searchSortType; };
_searchSortOrder.getOrderFromCookie = function() { return conf.searchSortOrder; };
content.load_org = content.load;
content.load = $.proxy(function(params, callback) {
var word = this.getSearchWord();
if (this.getSearchEngineType() !== 'sugoi' || word.length <= 0 || word.match(/(sm|nm|so)\d+/)) {
// 新検索ではもしかして~が取得できないため、検索ワードに動画IDっぽい文字列が含まれてる場合は旧タグ検索を使う。
this.setLastSearchEngineType('normal');
params.sort  = 'n';
params.order = 'd';
this.load_org(params, callback);
} else {
this.setLastSearchEngineType('sugoi');
params = this.getParams();
this._newSearchWrapper.load(params, function(err, r###lt) {
console.log('%cNewNicoSearchWrapper r###lt', 'color: green;', r###lt);
callback(err, r###lt);
});
}
}, content);
content.setSearchEngineType('sugoi');//conf.searchEngine);
var
overrideSearchSortOrder = function(proto) { // ソート順を記憶するためのフック
proto.getSort_org  = proto.getSort;
proto.getSort = function() {
var sort = conf.searchSortType;
if ((sort === '_hot' || sort === '_popular'  || sort === '_explore' || sort === '_id') && content.getLastSearchEngineType() !== 'sugoi') {
// 通常検索で新検索にしかないソート順だったらデフォルトのnを返す
return 'n';
}
return conf.searchSortType;
};
proto.setSort_org  = proto.setSort;
proto.setSort = function(type, sort)  {
conf.setValue('searchSortType', sort);
SearchSortOrder.TAG_DEFAULT_SORT = sort;
this.setSort_org(type, sort);
};
proto.getOrder_org = proto.getOrder;
proto.getOrder = function() {
return conf.searchSortOrder;
};
proto.setOrder_org = proto.setOrder;
proto.setOrder = function(type, order) {
if (content.getLastSearchEngineType() === 'sugoi') { // 新検索の時だけソート順を記憶
SearchSortOrder.TAG_DEFAULT_ORDER = order;
conf.setValue('searchSortOrder', order);
}
this.setOrder_org(type, order);
};
},
overrideSearchContentView = function(proto, relatedTag) {
proto._updateRelatedTag = function() {
if (!conf.enableRelatedTag) { return; }
var word = this._content._originalWord;
relatedTagView.clear();
if (typeof word === 'string' && word.length > 0) {
this._$header.append(relatedTagView.getView());
relatedTag.load(word, function(err, r###lt) {
console.log('SearchContentView._updateRelatedTag', err, r###lt);
if (err) {
console.log('load suggest fail', err, r###lt);
} else {
relatedTagView.update(r###lt.values);
}
});
}
};
proto.detach_org = proto.detach;
proto.detach = function() {
this.detach_org();
newSearchOptionView.detach();
relatedTagView.detach();
};
proto.onUpdate_org = proto.onUpdate;
proto.onUpdate = function() {
this.onUpdate_org();
this._$content.find('.searchBox').after(newSearchOptionView.getView());
this._updateRelatedTag();
var engine = this._content.getLastSearchEngineType();
newSearchOptionView.refresh();
$('.videoExplorerBody')
.toggleClass('w_sugoiSearch',  engine === 'sugoi')
.toggleClass('w_normalSearch', engine !== 'sugoi');
};
proto.onError_org = proto.onError;
proto.onError = function() {
this.onError_org();
this._$header.append(newSearchOptionView.getView());
this._updateRelatedTag();
var engine = this._content.getLastSearchEngineType();
$('.videoExplorerBody')
.toggleClass('w_sugoiSearch',  engine === 'sugoi')
.toggleClass('w_normalSearch', engine !== 'sugoi');
};
};
overrideSearchSortOrder(SearchSortOrder.prototype);
overrideSearchContentView(View.prototype, relatedTag);
} // end initSearchContent
function initUserVideoContent($, conf, w) {
var VideoExplorerInitializer = require('watchapp/init/VideoExplorerInitializer');
var ContentType      = require('watchapp/components/videoexplorer/model/ContentType');
var vec         = VideoExplorerInitializer.videoExplorerController;
var explorer    = vec.getVideoExplorer();
var content     = explorer.getContentList().getContent(ContentType.USER_VIDEO);
var pager       = content._pager;
pager._pageItemCount = conf.searchPageItemCount;
pager._displayPageCount = 5;
EventDispatcher.addEventListener('on.config.searchPageItemCount', function(v) {
pager._pageItemCount = v;
});
} //
function initUploadedVideoContent($, conf, w) {
var VideoExplorerInitializer = require('watchapp/init/VideoExplorerInitializer');
var ContentType      = require('watchapp/components/videoexplorer/model/ContentType');
var vec         = VideoExplorerInitializer.videoExplorerController;
var explorer    = vec.getVideoExplorer();
var content     = explorer.getContentList().getContent(ContentType.UPLOADED_VIDEO);
var pager       = content._pager;
pager._pageItemCount = conf.searchPageItemCount;
pager._displayPageCount = 5;
EventDispatcher.addEventListener('on.config.searchPageItemCount', function(v) {
pager._pageItemCount = v;
});
} //
var isSquareCssInitialized = false;
function initSquareThumbnail() {
var isSquare = true;// !!conf.squareThumbnail;
if (isSquare && !isSquareCssInitialized) {
var __css__ = Util.here(function() {/*
{* 元のCSSを打ち消すためにやや冗長 *}
#videoExplorer .noImage,
#videoExplorer.w_adjusted .item .thumbnail {
display: none !important;
}
#videoExplorer .thumbnailContainer {
background-size: contain;
background-repeat: no-repeat;
background-position: center center;
}
#videoExplorer.w_adjusted .column4        .thumbnailContainer,
#videoExplorer.w_adjusted .smallThumbnail .thumbnailContainer {
width: 130px; height: 100px;
margin-right: 7px;
border: 1px solid #888;
}
#videoExplorer.w_adjusted .column4        .uadFrame,
#videoExplorer.w_adjusted .smallThumbnail .uadFrame,
#videoExplorer.w_adjusted .uadTagRelated .uadFrame {
width: 130px; height: 100px;
background-size: 100% 100%;
}
#videoExplorer.w_adjusted .uadTagRelated .default .itemList .item .imageContainer {
width: 130px; height: 100px;
}
#videoExplorer.w_adjusted .column1 .item .thumbnailContainer {
border: 1px solid #888;
margin-right: 8px;
}
#videoExplorer.w_adjusted .column1 .item.smallThumbnail .thumbnailContainer {
border-width: 0px 15px 0px 15px;
border-color: #888;
}
*/});
addStyle(__css__, 'squareThumbnailCss');
isSquareCssInitialized = true;
}
//$('#videoExplorer').toggleClass('squareThumbnail', isSquare);
} //
function initPageBottom($, conf, w) {
function updateHideVideoExplorerExpand(v) {
$('#content, #outline').toggleClass('w_hideSearchExpand', v === true);
}
function updateIchibaVisibility(v) {
$('#outline').toggleClass('noIchiba', v === 'hidden');
}
function updateReviewVisibility(v) {
$('#outline').toggleClass('noReview', v === 'hidden');
}
function updateBottomContentsVisibility(v) {
$('#bottomContentTabContainer, #footer').toggleClass('noBottom', v === 'hidden');
}
EventDispatcher.addEventListener('on.config.hideVideoExplorerExpand',     updateHideVideoExplorerExpand);
EventDispatcher.addEventListener('on.config.ichibaVisibility',            updateIchibaVisibility);
EventDispatcher.addEventListener('on.config.reviewVisibility',            updateReviewVisibility);
EventDispatcher.addEventListener('on.config.bottomContentsVisibility',    updateBottomContentsVisibility);
if (conf.hideVideoExplorerExpand === true) { updateHideVideoExplorerExpand(true); }
if (conf.ichibaVisibility    !== 'visible') { updateIchibaVisibility(conf.ichibaVisibility); }
if (conf.reviewVisibility    !== 'visible') { updateReviewVisibility(conf.reviewVisibility); }
if (conf.bottomContentsVisibility !== 'visible') { updateBottomContentsVisibility(conf.bottomContentsVisibility); }
var $bottomToggle = $('<div class="toggleBottom"><div class="openBottom">▽</div><div class="closeBottom">△</div></div>');
$bottomToggle.on('click', function() {
var v = conf.bottomContentsVisibility;
conf.setValue('bottomContentsVisibility', v === 'hidden' ? 'visible' : 'hidden');
//ConfigPanel.refresh();
}).attr('title', '市場・レビューの開閉');
$('#footer').append($bottomToggle);
} //
function initShortcutKey() {
var list = [
{name: 'shortcutTogglePlay',        exec: function(e) {
WatchController.togglePlay();
}},
{name: 'shortcutDefMylist',          exec: function(e) {
WatchController.addDefMylist();
}},
{name: 'shortcutMylist',             exec: function(e) {
$('#mylist_add_frame').find('.mylistAdd').click();
}},
{name: 'shortcutOpenDefMylist',      exec: function(e) {
WatchController.showDeflist();
WatchController.scrollToVideoPlayer(true);
}},
{name: 'shortcutOpenSearch',         exec: function(e) {
WatchController.openSearch();
if (!$('body').hasClass('content-fix')) {
WatchController.scrollToVideoPlayer(true);
}
}},
{name: 'shortcutOpenRecommend',      exec: function(e) {
WatchController.openRecommend();
if (!$('body').hasClass('content-fix')) {
WatchController.scrollToVideoPlayer(true);
}
}},
{name: 'shortcutScrollToNicoPlayer', exec: function(e) {
WatchController.scrollToVideoPlayer(true);
}},
{name: 'shortcutCommentVisibility',  exec: function(e) {
WatchController.commentVisibility('toggle');
}},
{name: 'shortcutShowOtherVideo',     exec: function(e) {
WatchController.openVideoOwnersVideo();
}},
{name: 'shortcutMute',               exec: function(e) {
WatchController.mute('toggle');
}},
{name: 'shortcutDeepenedComment',    exec: function(e) {
WatchController.deepenedComment('toggle');
}},
{name: 'shortcutToggleStageVideo',   exec: function(e) {
WatchController.toggleStageVideo();
}},
{name: 'shortcutInvisibleInput',   exec: function(e) {
$('.invisibleCommentInput').focus();
}}
];
for (var v in list) {
var n = list[v].name;
list[v].keyMatch = KeyMatch.create(conf[n]);
}
ConfigPanel.addChangeEventListener(function(name, newValue, oldValue) {
for (var v in list) {
var n = list[v].name;
if (n === name) {
list[v].keyMatch = KeyMatch.create(newValue);
}
}
});
$('body').on('keydown.watchItLater', function(e) {
// 一部のキーボードについているMusic Key(正式名称不明)に対応 Chromeしか拾えない?
if (e.keyCode === 178) {  // 停止
WatchController.togglePlay();
} else
if (e.keyCode === 179) { // 一時停止
WatchController.togglePlay();
} else
if (e.keyCode === 177) { // 前の曲
if (WatchController.vpos() > 2000) {
WatchController.vpos(0);
} else {
WatchController.prevVideo();
}
} else
if (e.keyCode === 176) { // 次の曲
WatchController.nextVideo();
}
if (e.target.tagName === 'SELECT' || e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') {
return;
}
// 全画面時はFlashにフォーカスがなくてもショートカットキーが効くようにする
for (var v in list) {
var n = list[v].name;
if (list[v].keyMatch.test(e)) {
list[v].exec(e);
}
}
});
} //
function initNicoS($, conf, w) {
WatchJsApi.nicos.addEventListener('nicoSJump', function(e) {
if (conf.ignoreJumpCommand) {
e.cancel();
Popup.show('「@ジャンプ」コマンドをキャンセルしました');
}
});
var seekCount = 0;
require('watchapp/model/player/NicoSClientConnector').addEventListener('nicoSSeek', function(e) {
seekCount++;
if (conf.nicoSSeekCount < 0) return;
if (seekCount > conf.nicoSSeekCount) {
e.cancel();
}
});
// 動画が切り替わったか、最後まで視聴したらカウンターリセット
EventDispatcher.addEventListener('onVideoInitialized', function() {
seekCount = 0;
});
EventDispatcher.addEventListener('onVideoEnded', function() {
seekCount = 0;
});
} //
function initMouse() {
ConfigPanel.addChangeEventListener(function(name, newValue, oldValue) {
if (name === 'mouseClickWheelVolume') {
if (oldValue === 0) {
initWheelWatch();
} else
if (newValue === 0) {
$(document)
.unbind('mousewheel.watchItLaterWheelWatch')
.unbind('mousedown.watchItLaterWheelWatch')
.unbind('mouseup.watchItLaterWheelWatch');
}
}
});
function initWheelWatch() {
var leftDown = false, rightDown = false, isVolumeChanged = false;
var event = {
cancel: false,
reset: function() { this.cancel = false; return this; },
preventDefault: function() { this.cancel = true;}
};
$(document).on('mousewheel.watchItLaterWheelWatch', function(e, delta) {
var button = -1;
// TODO: マジックナンバーを
if (typeof e.buttons === 'number') { // firefox
button = e.buttons;
} else { // chrome
if (leftDown)  { button = 1; }
else
if (rightDown) { button = 2; }
}
if (button < 1) {
EventDispatcher._dispatch('onWheelNoButton', e, delta);
return;
}
EventDispatcher.dispatch('onWheelAndButton', event.reset(), delta, button);
if (event.cancel) {
e.preventDefault();
return;
}
if (conf.mouseClickWheelVolume !== button) {
return;
}
var v = WatchController.volume(), r;
isVolumeChanged = true;
// 音量を下げる時は「うわ音でけぇ!」
// 音量を上げる時は「ちょっと聞こえにくいな」…というパターンが多いので、変化の比率が異なる
if (delta > 0) {
v = Math.max(v, 1);
r = (v < 5) ? 1.3 : 1.1;
v = WatchController.volume(v * r);
} else {
v = WatchController.volume(Math.floor(v / 1.2));
}
e.preventDefault();
}).on('mousedown.watchItLaterWheelWatch', function(e) { // chromeはホイールイベントでe.buttonsが取れないため
if (e.which === 1) leftDown  = true;
if (e.which === 3) rightDown = true;
}).on('mouseup.watchItLaterWheelWatch', function(e) {
if (e.which === 1) leftDown  = false;
if (e.which === 3) rightDown = false;
}).on('contextmenu.watchItLaterWheelWatch', function(e) {
if (isVolumeChanged) {
e.preventDefault();
}
isVolumeChanged = false;
});
}
window.setTimeout(function() { initWheelWatch(); }, 5000);
} // end initMouse
function initTouch() {
var touchInitialized = false;
TouchEventDispatcher.onflick(function(e) {
var se = e.startEvent;
if (!conf.enableQTouch) {return; }
if (e.direction === 'right') {
if (se.target.id === 'playerTabWrapper') {
$(se.target).addClass('w_active');
}
if (!touchInitialized) {
$('#mylist_add_frame, #leftPanelTabContainer, .videoExplorerMenu, #playerTabWrapper').addClass('w_touch');
$('.userProfile, .r###ltPagination, #searchR###ltContainer select, .playlistMenuPopup').addClass('w_touch');
isTouchActive = true;
touchInitialized = true;
}
} else
if (e.direction === 'left') {
if (se.target.tagName === 'DIV' &&
$.contains('#playerTabWrapper', se.target)) {
$('#playerTabWrapper').removeClass('w_active');
}
}
});
} //
function initOtherCss() {
var __dynamic_css_template__ = Util.here(function() {/*
.full_with_browser.w_fullScreenMenu #nicoHeatMap {
transform: scaleX($scale); -webkit-transform: scaleX($scale); display: block;
}
*/});
var exStyle = null;
var updateDynamicCss = function() {
var css = __dynamic_css_template__;
var innerWidth = $('body').innerWidth();
css = css.split('$scale').join($('body').innerWidth() / 100);
if (exStyle) {
exStyle.innerHTML = css;
return exStyle;
} else {
return addStyle(css, 'expression');
}
};
exStyle = updateDynamicCss();
EventDispatcher.addEventListener('onWindowResizeEnd', function() {
updateDynamicCss();
});
var __gpuLayer__ = (function() {/*
body.videoExplorer.content-fix #playerTabWrapper,
body.videoExplorer.content-fix .videoExplorerMenu,
body.videoExplorer.content-fix #playlist,
{*#playerTabWrapper  .playerCommentPanel*}
body:not(.full_with_browser) .mylistPopupPanel.fixed
{
-moz-transform: translateZ(0);
-webkit-transform: translateZ(0);
transform: translateZ(0);
}
{* Firefoxだと問題がある要素はこちら *}
body.videoExplorer.content-fix #leftPanel,
body.videoExplorer.content-fix #content,
#popupMarquee
{
-webkit-transform: translateZ(0);
}
*/}).toString().match(/[^]*\/\*([^]*)\*\/\}$/)[1]
.replace(/\{\*/g, '/*').replace(/\*\}/g, '*/');
if (conf.enableGpuLayer) {
addStyle(__gpuLayer__, 'watchItLaterGpuLayer');
}
var __debug_css__ = Util.here(function() {/*
.videoExplorer        #playerContainerWrapper, .videoExplorer        #external_nicoplayer,
.videoExplorerOpening #playerContainerWrapper, .videoExplorerOpening #external_nicoplayer
{
{*transition: width 0.4s ease, height 0.4s ease;*}
}
#playerAlignmentArea .toggleCommentPanel {
{*transition: 0.4s ease-in-out;*}
}
{*
body:not(.videoExplorer):not(.full_with_browser) #playerNicoplayer,
body:not(.videoExplorer):not(.full_with_browser) #playerAlignmentArea{
transition: width  0.4s ease;
}
body:not(.videoExplorer):not(.full_with_browser) #nicoplayerContainer{
transition: height 0.4s ease 0.4s;
}
*}
*/});
if (conf.debugMode) addStyle(__debug_css__, 'watchItLater_debug_css');
} // end initOtherCss
function initCustomPlayerSize($, conf, w) {
var tpl = Util.here(function() {/*
body.size_normal.w_size_custom:not(.videoExplorer):not(.full_with_browser) #playerAlignmentArea
{ width: {$alignmentAreaWidth}px; }
body.size_normal.w_size_custom:not(.videoExplorer):not(.full_with_browser) .w_wide #playerAlignmentArea
{ width: {$alignmentAreaWideWidth}px; }
body.size_normal.w_size_custom:not(.videoExplorer):not(.full_with_browser) #nicoplayerContainer {
height: {$playerHeight}px !important;
}
body.size_normal.w_size_custom:not(.videoExplorer):not(.full_with_browser) #playerNicoplayer
{ width: {$playerWidth}px !important;}
body.size_normal.w_size_custom:not(.videoExplorer):not(.full_with_browser) #external_nicoplayer
{ width: {$playerWidth}px !important; height: {$playerHeight}px !important; }
body.size_normal.w_size_custom:not(.videoExplorer):not(.full_with_browser) #nicoHeatMapContainer {
width: {$playerWidth}px !important;
}
body.size_normal.w_size_custom:not(.videoExplorer):not(.full_with_browser) #nicoHeatMap {
transform: scaleX({$heatMapScale}); -webkit-transform: scaleX({$heatMapScale});
}
body.size_normal.w_size_custom:not(.videoExplorer):not(.full_with_browser) #smart_music_kiosk {
-webkit-transform: scaleX({$songriumScale}); -webkit-transform-origin: 0 0;
}
body.size_normal.w_size_custom:not(.videoExplorer):not(.full_with_browser) #inspire_category {
left: {$songriumCategoryLeft}px !important;
}
*/});
var PROFILE_SET = {
'WQHD':   [2560, 1440],
'1080p':  [1920, 1080],
'HD+':    [1600,  900],
'WXGA+':  [1400,  810],
'WXGA':   [1366,  768],
'720p':   [1280,  720],
'WSVGA+': [1152,  648],
'WSVGA':  [####,  576],
'QHD':    [ 960,  540]//, // 元より小さいパターンもサポートする?
//        'WVGA':   [ 854,  480],
//        'NORMAL': [ 640,  360],
//        'SMALL':  [ 512,  288],
//        'ECO':    [ 352,  200],
};
var CONTROL_HEIGHT = 46, INPUT_HEIGHT = 30, PLAYER_TAB_WIDTH = 326 + 10, PLAYER_TAB_WIDTH_WIDE = 420 + 10, TAB_MARGIN = 0;
var SONGRIUM_WIDTH = 898;
var HORIZONTAL_MARGIN = 1.05; // 両端に 2.5% x 2 のマージンがある
var $videoHeader = $('#videoHeader');
var getTargetSize = function(targetWidth, targetHeight) {
var plWidth  = Math.round(targetWidth * HORIZONTAL_MARGIN);
var plHeight = targetHeight + CONTROL_HEIGHT + INPUT_HEIGHT;
var alWidth  = plWidth + PLAYER_TAB_WIDTH;
var alWidthW = plWidth + PLAYER_TAB_WIDTH_WIDE;
return {
playerWidth:            plWidth,
playerHeight:           plHeight,
alignmentAreaWidth:     alWidth,
alignmentAreaWideWidth: alWidthW,
heatMapScale:           plWidth / 100,
songriumScale:          plWidth / SONGRIUM_WIDTH,
songriumCategoryLeft:   plWidth + 32
};
};
var suggestProfile = function() {
var iw = $(window).innerWidth(), ih = $(window).innerHeight();
var hh = (WatchController.isFixedHeader() ? $("#siteHeader").outerHeight() : 0);
iw -= (conf.wideCommentPanel ? PLAYER_TAB_WIDTH_WIDE : PLAYER_TAB_WIDTH);
iw -= TAB_MARGIN;
ih -= hh;
for (var v in PROFILE_SET) {
var w = PROFILE_SET[v][0], h = PROFILE_SET[v][1];
if (w * HORIZONTAL_MARGIN <= iw && h <= ih) {
return {w: w, h: h, name: v};
}
}
return null;
};
var generateCss = function() {
var profile = '';
if (PROFILE_SET[conf.customPlayerSize]) {
var s = PROFILE_SET[conf.customPlayerSize];
profile = {w: s[0], h: s[1], name: conf.customPlayerSize};
} else {
profile = suggestProfile();
}
if (!profile) return {css: '', profile: ''};
var ts = getTargetSize(profile.w, profile.h);
var css = tpl;
for (var v in ts) {
css = css.split('{$' + v + '}').join(ts[v]);
}
return {css: css, profile: profile};
};
var customStyleElement = null, lastCssName = '';
var updateStyle = function() {
if (WatchController.isFullScreen() || WatchController.isSearchMode()) {
return;
}
var r###lt = generateCss();
var css = r###lt.css, profile = r###lt.profile, name = profile.name;
if (lastCssName === name) {
return;
}
lastCssName = name;
if (customStyleElement) {
customStyleElement.innerHTML = css;
} else {
customStyleElement = addStyle(css, 'customPlayerSize');
}
EventDispatcher.dispatch('onPlayerAlignmentAreaResize');
};
var toggleCustomSize = function(v) {
if (typeof v === 'boolean') {
$('body').toggleClass('w_size_custom', v);
} else {
$('body').toggleClass('w_size_custom');
}
};
var clearStyle = function() {
if (customStyleElement) {
customStyleElement.innerHTML = '';
toggleCustomSize(false);
}
lastCssName = '';
};
if (conf.customPlayerSize !== '') {
updateStyle();
toggleCustomSize();
}
EventDispatcher.addEventListener('on.config.customPlayerSize', function(v) {
if (v === '') {
clearStyle();
} else {
updateStyle();
toggleCustomSize(true);
}
});
EventDispatcher.addEventListener('on.config.wideCommentPanel', function(v) {
if (conf.customPlayerSize !== '') {
updateStyle();
}
});
EventDispatcher.addEventListener('onWindowResizeEnd', function() {
if (conf.customPlayerSize !== '') {
updateStyle();
}
});
if (conf.debugMode) {
WatchItLater.debug.customSize = {
suggestProfile:   suggestProfile,
getTargetSize:    getTargetSize,
generateCss:      generateCss,
updateStyle:      updateStyle,
toggleCustomSize: toggleCustomSize
};
}
} //
function initStageVideo($, conf, w) {
var onStageVideoAvailabilityUpdated = function(v) {
$('#nicoplayerContainerInner').toggleClass('stageVideo', v);
};
EventDispatcher.addEventListener('onFirstVideoInitialized', function() {
onStageVideoAvailabilityUpdated(WatchController.isStageVideoAvailable());
if (conf.forceEnableStageVideo) {
try {$('#external_nicoplayer')[0].setIsForceUsingStageVideo(true);  } catch (e) { console.log(e);}
}
});
var PlayerInitializer = require('watchapp/init/PlayerInitializer');
var pac = PlayerInitializer.playerAreaConnector;
pac.addEventListener('onStageVideoAvailabilityUpdated', onStageVideoAvailabilityUpdated);
// console.log('StageVideo', $('#external_nicoplayer')[0].isStageVideoSupported() ? 'supported' : 'not supported');
// console.log('ColorSpaces', $('#external_nicoplayer')[0].getStageVideoSupportedColorSpaces());
} //
/**
* Chromeなら ALT+C
* Firefoxなら ALT+SHIFT+C で召喚
*
* どこでもコメント入力開始する隠し機能
*
* :m[0-9a-p] xxxxx でマイリストする機能もある
*
**/
function initInvisibleCommentInput($, conf, w) {
var $view = $(Util.here(function() {/*
<div class="invisibleInput">
<form action="javascript: void(0);">
<input type="text" value="" autocomplete="on" name="chat" accesskey="c"
list="myMylist" placeholder="コメント入力" class="invisibleCommentInput"
maxlength="75"
></form>
<label><input type="checkbox" class="autoPause" checked="checked">動画を自動で一時停止する</label>
</div>
*/}));
var css = Util.here(function() {/*
.invisibleInput {
position: fixed; z-index: 10000;
left: 100px; bottom: -100px; width: 300px;
padding: 16px;
border: 1px solid black;
background: #eee;
transition: bottom 0.4s ease 0.1s;
}
.invisibleInput.active {
bottom: 50px;
transition: bottom 0.4s ease;
box-shadow: 2px 2px 2px #333;
}
.invisibleInput .invisibleCommentInput {
width: 100%; font-size: 140%;
}
*/});
var $dataList = $('<datalist id="myMylist"></datalist>');
var $form      = $view.find('form');
var $input     = $view.find('input');
var $autoPause = $view.find('.autoPause').prop('checked', conf.autoPauseInvisibleInput);
var prevent = function(e) { e.stopPropagation(); e.preventDefault(); };
var preventEsc = function(e) { if (e.keyCode === 27) { prevent(e); } };
var isAutoPause = function() { return !!$autoPause.prop('checked'); };
var mylistList = [];
var
onMylistUpdate = function(status, r###lt) {
if (status === "ok") {
Popup.show('マイリストに追加しました');
} else {
Popup.alert('マイリスト追加に失敗: ' + r###lt.error.description);
}
}, addMylist = function(n, d) {
var num = parseInt(n, 36);
var description = d || '';
if (num === 0) {
Mylist.addDeflistItem(WatchController.getWatchId(),                     onMylistUpdate, description);
} else
if (mylistList[num]) {
Mylist.addMylistItem (WatchController.getWatchId(), mylistList[num].id, onMylistUpdate, description);
}
}, showMylist = function(n) {
var num = parseInt(n, 36);
if (num === 0) {
WatchController.showDeflist();
} else
if (mylistList[num]) {
WatchController.showMylist(mylistList[num].id);
}
}, seekVideo = function(v) {
var vpos = WatchController.vpos(), currentVpos = vpos;
if (v.match(/^([\-+]\d+)/)) {
vpos += parseInt(RegExp.$1, 10) * 1000;
} else
if (v.match(/^\d+$/)) {
vpos  = parseInt(v, 10) * 1000;
} else
if (v.match(/^(\d+):(\d+)$/)) {
vpos = parseInt(RegExp.$1, 10) * 60 * 1000 + parseInt(RegExp.$2, 10) * 1000;
}
vpos = Math.max(vpos, 0);
if (vpos != currentVpos) {
WatchController.vpos(vpos);
}
};
var isPlaying = false;
$input
.on('focus',    function(e) {
isPlaying = WatchController.isPlaying();
if (isAutoPause()) {
WatchController.pause();
}
$view.addClass('active');
}).on('blur',     function(e) {
if (isAutoPause() && isPlaying) {
WatchController.play();
}
$view.removeClass('active');
}).on('keyup', function(e) {
if (e.keyCode === 27) { // ESC
prevent(e);
$input.blur();
}
}).on('keydown', preventEsc).on('keyup', preventEsc);
$autoPause.on('click', function() {
conf.setValue('autoPauseInvisibleInput', !!$autoPause.prop('checked'));
});
$form
.on('submit', function(e) {
//prevent(e);
var val = $.trim($input.val());
if (val.match(/^:m([0-9a-p])(.*)/)) {
addMylist(RegExp.$1, RegExp.$2);
} else
if (val.match(/^:o([0-9a-p])/)) {
showMylist(RegExp.$1);
} else
if (val.match(/^:s[  \s](.+)/)) {
WatchController.nicoSearch(RegExp.$1, 'keyword');
} else
if (val.match(/^:t[  \s](.+)/)) {
WatchController.nicoSearch(RegExp.$1, 'tag');
} else
if (val.match(/^:v[  \s]([0-9:+\-]+)$/)) {
seekVideo(RegExp.$1);
} else {
WatchController.postComment(val);
}
setTimeout(function() { $input.val(''); } , 100);
$input.blur();
});
Mylist.loadMylistList(function(list) {
mylistList = list.concat();
mylistList.unshift({description: '', id: '', name: 'とりあえずマイリスト'});
var isFx = Util.Browser.isFx();
var tmp = [];
for (var i = 0, len = mylistList.length; i < len; i++) {
var c = i.toString(36);
// それぞれのブラウザで補完しやすい形式に
if (isFx) { // Fx
tmp.push('<option value=":m' + c + '">:m'+c+'\t 「' + mylistList[i].name + '」に追加</option>');
tmp.push('<option value=":o' + c + '">:o'+c+'\t 「' + mylistList[i].name + '」を開く</option>');
} else {    // Chrome
tmp.push('<option value=":m' + c + '">「' + mylistList[i].name + '」に追加</option>');
tmp.push('<option value=":o' + c + '">「' + mylistList[i].name + '」を開く</option>');
}
}
tmp.sort();
if (isFx) {
tmp.push('<option value=":s ">:s [キーワード検索]</option>');
tmp.push('<option value=":t ">:t [タグ検索]</option>');
tmp.push('<option value=":v ">:v [シーク(秒)]</option>');
} else {
tmp.push('<option value=":s ">キーワード検索</option>');
tmp.push('<option value=":t ">タグ検索</option>');
tmp.push('<option value=":v ">シーク(秒)</option>');
}
$dataList.html(tmp.join('\n'));
});
addStyle(css, 'invisibleInput');
$('body').append($view).append($dataList);
} //
function initHeatMap($, conf, w) {
if (!conf.enableHeatMap) return;
var PlayerInitializer = require('watchapp/init/PlayerInitializer');
var npc = PlayerInitializer.nicoPlayerConnector;
var canvasWidth = 100, canvasHeight = 12;
var comments = [], duration = 0, canvas = null, context = null;
var commentReady = false, videoReady = false, updated = false, palette = [];
var __css__ = Util.here(function(){/*
#nicoHeatMapContainer {
position: absolute; z-index: 200;
{*bottom: 0px;*} left: 0;
width: 672px;
background: #000; height: 6px;
overflow: hidden;
}
.setting_panel #nicoHeatMapContainer { display: none; opacity: 0; }
.size_normal #nicoHeatMapContainer {
width: 898px;
}
{*.oldTypeCommentInput*} #nicoHeatMapContainer {
bottom: 29px;
display: none;
}
#nicoHeatMap {
position: absolute; top: 0; left: 0;
transform-origin: 0 0 0;-webkit-transform-origin: 0 0 0;
transform: scaleX(6.72);-webkit-transform: scaleX(6.72);
}
{* パズルみたいになってきた *}
body.size_normal:not(.full_with_browser) #content:hover #nicoHeatMapContainer,
body.size_medium:not(.full_with_browser) #content:hover #nicoHeatMapContainer,
body.videoExplorer #content.w_adjusted:hover #nicoHeatMapContainer,
body:not(.full_with_browser) #nicoHeatMapContainer.displayAlways {
display: block;
}
#nicoHeatMapContainer.displayAlways {
cursor: pointer;
}
.size_normal #nicoHeatMap {
transform: scaleX(8.98); -webkit-transform: scaleX(8.98);
}
.setting_panel #nicoHeatMapContainer, .full_with_browser #nicoHeatMapContainer, .size_small #content:not(.w_adjusted) #nicoHeatMapContainer {
display: none;
}
.full_with_browser.w_fullScreenMenu #nicoHeatMapContainer {
display: block;
width: 100%;
}
.full_with_browser.w_fullScreenMenu {*.oldTypeCommentInput*} #nicoHeatMapContainer {
bottom: 29px;
height: 6px;
}
body.full_with_browser.w_fullScreenMenu:fullscreen                 #playerContainer #nicoHeatMapContainer,
.full_with_browser.w_fullScreenMenu.hideCommentInput                  #playerContainer #nicoHeatMapContainer {
position: fixed !important;gtgt
}
body.full_with_browser.w_fullScreenMenu.fullWithPlaylist:fullscreen #playerContainer #nicoHeatMapContainer,
.full_with_browser.w_fullScreenMenu.hideCommentInput.fullWithPlaylist #playerContainer #nicoHeatMapContainer {
bottom: 167px;
}
*/});
addStyle(__css__, 'NicoHeatMapCss');
var pv = require('watchapp/init/PlayerInitializer').rightSidePanelViewController.getPlayerPanelTabsView();
var cpv = pv._commentPanelView;
//cpv.showTooltip = function() {};
//advice.after(npc, 'onCommentListInitialized', $.proxy(onCommentListInitialized, this));
EventDispatcher.addEventListener('onCommentListInitialized', function() {
w.setTimeout(function() {
commentReady = true;
update();
}, 5000);
});
EventDispatcher.addEventListener('onVideoInitialized', function() {
w.setTimeout(function() {
videoReady = true;
update();
}, 5000);
});
EventDispatcher.addEventListener('onVideoChangeStatusUpdated', function() {
commentReady = videoReady = updated = false;
clearCanvas();
});
var update = function() {
if (!commentReady || !videoReady || updated) return;
updated = true;
initCanvas();
getComments();
getDuration();
if (comments.length < 1 || duration < 1) {
return;
}
getHeatMap(function(map) {
var scale = duration >= canvasWidth ? 1 : (canvasWidth / duration);
var blockWidth = (canvasWidth / map.length) * scale;
for (i = map.length - 1; i >= 0; i--) {
context.fillStyle = palette[map[i]] || palette[0];
context.beginPath();
context.fillRect(i * scale, 0, blockWidth, canvasHeight);
}
});
};
var getComments = function() {
var pt = PlayerInitializer.rightSidePanelViewController.getPlayerPanelTabsView();
var cv = pt._commentPanelView;
comments = cv.getComments().getData();
};
var getDuration = function() {
var exp = document.getElementById('external_nicoplayer');//$('#external_nicoplayer')[0];
duration = exp.ext_getTotalTime(); //
};
var initCanvas = function() {
if (!canvas) {
var $container = $('<div id="nicoHeatMapContainer" />');
$container.on('dblclick', function(e) {
e.preventDefault();
e.stopPropagation();
var $this = $(this).toggleClass('displayAlways');
conf.setValue('heatMapDisplayMode', $this.hasClass('displayAlways') ? 'always' : 'hover');
});
canvas = document.createElement('canvas');
canvas.id = 'nicoHeatMap';
canvas.width  = canvasWidth;
canvas.height = canvasHeight;
$container.append(canvas);
$('#nicoplayerContainerInner').append($container);
context = canvas.getContext('2d');
if (conf.heatMapDisplayMode === 'always') {
$container.addClass('displayAlways');
}
initPalette();
}
clearCanvas();
};
var initPalette =  function() {
for (var c = 0; c < 256; c++) {
var
r = Math.floor((c > 127) ? (c / 2 + 128) : 0),
g = Math.floor((c > 127) ? (255 - (c - 128) * 2) : (c * 2)),
b = Math.floor((c > 127) ? 0 : (255  - c * 2));
palette.push('rgb(' + r + ', ' + g + ', ' + b + ')');
}
};
var clearCanvas = function() {
if (!context) return;
context.fillStyle = palette[0];
context.beginPath();
context.fillRect(0, 0, canvasWidth, canvasHeight);
};
var getHeatMap = function(callback) {
var map = new Array(100), i = map.length; while(i > 0) map[--i] = 0;
var exp = $('#external_nicoplayer')[0];
var ratio = duration > map.length ? (map.length / duration) : 1;
for (i = comments.length - 1; i >= 0; i--) {
var pos = comments[i].vpos , mpos = Math.min(Math.floor(pos * ratio / 1000), map.length -1);
map[mpos]++;
}
var max = 0;
for (i = map.length - 4; i >= 0; i--) max = Math.max(map[i], max); // 末尾は固まってる事があるので参考にしない
if (max > 0) {
var rate = 255 / max;
for (i = map.length - 1; i >= 0; i--) {
map[i] = Math.min(255, Math.floor(map[i] * rate));
}
}
if (typeof callback === 'function') {
callback(map);
}
};
} // end of initHeatMap
/**
* 既存のポップアップの難点
*
* ・閉じる機能がなく、邪魔でも消えるまで待つしかない
* ・消えるまでの時間が毎回違う?
* ・クリックしたら消えるのかなと思ったらマイページに飛ばされる
* ・Chrome以外では動画プレイヤーの上に表示できない (半透明の部分が欠ける)
* ・↑によってプレイヤー上でフェードイン・アウトが出来ないため、まったく見えない状態から突然出現したようになる
* ・タイマー処理がバグっていて、一個目の表示中に2個目を連続表示すると2個目がすぐ消える
*
*  … という所があんまりなので、パッチをあてて直す。
*  ・Chrome以外は半透明をやめて画面外からのスライドにする
* ・CSS3アニメーションを使う(jQueryより軽い)
*  ・クリックでマイページに飛ぶのをやめて、クリックで消えるようにする
*  ・マウスオーバーしてる間は引っ込まない
*  ・消えるまでの時間を4秒に固定
*
*/
function initPopupMarquee() {
if (!conf.replacePopupMarquee) { return; }
var
PopupMarqueeInitializer = require('watchapp/init/PopupMarqueeInitializer'),
marquee  = PopupMarqueeInitializer.popupMarqueeViewController,
itemList = marquee.itemList,
$popup   = $('#popupMarquee'),
$inner   = $popup.find('.popupMarqueeContent'),
closeTimer = null,
popupDuration = 6000;
var
resetCloseTimer = function() {
if (closeTimer) {
clearTimeout(closeTimer);
closeTimer = null;
}
},
setCloseTimer  = function() {
resetCloseTimer();
closeTimer = setTimeout(function() {
disappear();
closeTimer = null;
}, popupDuration);
},
onData         = function(data) {
$inner.html(data);
$popup.removeClass('hide').removeClass('show');
setTimeout(function() {
$popup.removeClass('hide').addClass('show');
}, 100);
setCloseTimer();
},
disappear      = function() {
$popup.removeClass('show');
resetCloseTimer();
setTimeout(function() {
if (!$popup.hasClass('show')) $popup.addClass('hide');
setTimeout(function() {
itemList.next();
}, Math.random() * 5000 + 5000);
}, 500);
},
__css__ = Util.here(function() {/*
#popupMarquee      {
-webkit-filter: opacity(  0%); {* chrome以外はflashの上に半透明要素を置けない *}
background: #000 !important;
transition: -webkit-filter 0.25s ease-in,  top 0.5s ease-in,  bottom 0.5s ease-in;  display: block;
}
#popupMarquee.show {
-webkit-filter: opacity(100%);
transition: -webkit-filter 1.00s ease-out, top 0.5s ease-out, bottom 0.5s ease-out; display: block;
}
#popupMarquee.hide {
opacity: 0; z-index: -1;
}
#popupMarquee.popupMarqueeTopRight:not(.show),    #popupMarquee.popupMarqueeTopLeft:not(.show)    { top:    -600px; }
#popupMarquee.popupMarqueeBottomRight:not(.show), #popupMarquee.popupMarqueeBottomLeft:not(.show) { bottom: -600px; }
*/});
addStyle(__css__, 'popupMarqueeFix');
itemList.eventTypeListenerMap.popup = []; //itemList.removeEventListener('popup', marquee.onData);
$popup
.css({opacity: ''})
.off('click').off('mouseover').off('mouseleave').off('mousemove')
.on('mouseover', resetCloseTimer)
.on('mouseout',    setCloseTimer)
.on('click', disappear);
marquee.onData    = $.proxy(onData,    marquee);
marquee.disappear = $.proxy(disappear, marquee);
itemList.addEventListener('popup', $.proxy(onData, marquee));
} //
function initScroll($, conf, w) {
// 動画切り換え時にページの一番上までスクロールするようになったのを強引に阻止する
var WatchPageRouter = require('watchapp/model/state/WatchPageRouter');
WatchPageRouter.getInstance()._scroll = function() {};
var beforePlayerOffsetTop = 0, $playerAlignmentArea = $('#playerAlignmentArea');
var $window = $(window);
var beforeReset = function() {
beforePlayerOffsetTop = $playerAlignmentArea.offset().top;
};
var afterReset = function() {
var diff = $playerAlignmentArea.offset().top - beforePlayerOffsetTop;
var scrollTop = $window.scrollTop();
$window.scrollTop(scrollTop + diff);
};
var watchInfoModel = require('watchapp/model/WatchInfoModel').getInstance();
watchInfoModel.addEventListener('beforeReset', beforeReset);
watchInfoModel.addEventListener('afterReset',  afterReset);
// 動画選択画面閉じた時にページの一番上までスクロールするようになったのを強引に阻止する
var WindowUtil = require('watchapp/util/WindowUtil');
WindowUtil.scroll_org = WindowUtil.scroll;
var no_thanks = function() { WindowUtil.scroll = function() {}; };
var restore = function() { WindowUtil.scroll = WindowUtil.scroll_org; };
var vv = require('watchapp/init/BottomContentInitializer').videoExplorerModeViewController;
vv.onVideoExplorerClose_org = vv.onVideoExplorerClose;
vv.onVideoExplorerClose = $.proxy(function() {
no_thanks();
this.onVideoExplorerClose_org();
restore();
WindowUtil.scrollFit('#playerContainerWrapper');
}, vv);
$ = conf = w = null;
} //
function initOther() {
var TagInitializer = require('watchapp/init/TagInitializer');
var PlayerInitializer = require('watchapp/init/PlayerInitializer');
if (conf.headerViewCounter) $('#siteHeaderInner').width($('#siteHeaderInner').width() + 200);
initAdditionalButtons();
initSquareThumbnail();
ConfigPanel.addChangeEventListener(function(name, newValue, oldValue) {
if (name === 'squareThumbnail') {
initSquareThumbnail();
} else
if (name === 'enableAutoTagContainerHeight') {
if (newValue) { TagInitializer.tagViewController.tagViewPinStatus.changeStatus(true); }
} else
if (name === 'enableMylistDeleteButton') {
$('.videoExplorerBody').toggleClass('enableMylistDeleteButton', newValue);
} else
if (name === 'enableYukkuriPlayButton') {
newValue ? Yukkuri.show() : Yukkuri.hide();
} else
if (name === 'playerBgStyle') {
$('#content')
.toggleClass('w_flat_gray',  newValue === 'gray')
.toggleClass('w_flat_white', newValue === 'white');
} else
if (name === 'compactVideoInfo') {
$('#content, #outline').toggleClass('w_compact', newValue);
} else
if (name === 'disableHorizontalScroll') {
$('body').toggleClass('w_disableHorizontalScroll', newValue);
} else
if (name === 'hideCommentPanelSocialButtons') {
$('#playerTabContainer').toggleClass('w_noSocial', newValue);
}
});
if (conf.enableMylistDeleteButton) $('.videoExplorerBody').addClass('enableMylistDeleteButton');
if (conf.playerBgStyle !== '') $('#content').addClass('w_flat_' + conf.playerBgStyle);
if (conf.compactVideoInfo) $('#content, #outline').addClass('w_compact');
onWatchInfoReset(watchInfoModel);
if (conf.enableYukkuriPlayButton) { Yukkuri.show(); }
if (conf.disableHorizontalScroll) $('body').addClass('w_disableHorizontalScroll');
if (conf.hideCommentPanelSocialButtons) $('#playerTabContainer').addClass('w_noSocial');
$('#videoHeaderMenu .searchText input').attr({'accesskey': '@'}).on('focus', function() {
WatchController.scrollTop(0, 400);
});
var overrideGenerateURL = function() {
var WatchPageInitializer = require('watchapp/init/WatchPageInitializer');
var wpc = WatchPageInitializer.watchPageController;
wpc.generateWatchURL_org = wpc.generateWatchURL;
wpc.generateWatchURL = $.proxy(function(s) {
var ret = this.generateWatchURL_org(s);
// これのせいで既読リンクの色が変わらないので除去
ret = ret.replace(/\/(videoExplorer|ichiba)/, '');
return ret;
}, wpc);
};
overrideGenerateURL();
// 再現性不明のエラーをとりあえず握りつぶしつつ自動再生を3/2までの仕様に戻す
var WindowUtil = require('watchapp/util/WindowUtil');
var overrrideWindowUtil = function() {
var wu = WindowUtil;
wu.checkInview_org = wu.checkInview;
wu.checkInview = function() { return true; };
//wu.checkInview = $.proxy(function(a) {
//  if (a.length < 0) { return true; }
//  try {
//    this.checkInview_org(a);
//  } catch (e) {
//    console.log('%cerror in WindowUtil.checkInview', 'color: red; ', e, a);
//    console.trace();
//  }
//}, wu);
};
overrrideWindowUtil();
// ニコる数を取得するためにコメントパネルがめちゃくちゃ重くなってるのを改善
var playerConfig = PlayerInitializer.nicoPlayerConnector.playerConfig;
if (conf.autoPlayIfWindowActive === 'yes') {
playerConfig.set({autoPlay: false});
}
if (conf.autoPlay2ndVideo) {
playerConfig.set({autoPlay: false});
EventDispatcher.addEventListener('onFirstVideoInitialized', function() {
WatchController.pause();
WatchController.vpos(0);
setTimeout(function() {
playerConfig.set({autoPlay: true});
}, 3000);
});
$(window).on('beforeunload.watchItLater.autoPlay2ndVideo', function(e) {
playerConfig.set({autoPlay: false});
});
}
var initializeMylistSortV2 = function() {
var VideoListSortUtil = require('watchapp/util/VideoListSortUtil');
var ArrayUtil = require('watchapp/util/ArrayUtil');
VideoListSortUtil.sort_org = VideoListSortUtil.sort;
VideoListSortUtil.sort = function(items, type, isSlice) {
if (type !== '6' && type !== '7') {
return items = VideoListSortUtil.sort_org(items, type, isSlice);
}
var sortParam = VideoListSortUtil._getSortParam(type);
var key = sortParam[0];
var pat = sortParam[1];
var asc = sortParam[2];
// ニコニコ動画のシステムでは銀魂や遊戯王など、大量の動画が同時に公開された場合に話数順にソートできない。
// そこで、「キーが同じだったら動画ID順にする」という処理を追加する。
//
// 動画IDの桁数が変わったりnm,sm,soが混在していると期待通りにならないが、今よりはだいぶマシ
var ad = asc ? 1 : -1;
var compNum = function(a, b) { return a[key] > b[key] ? ad : -ad; };
var compStr = function(a, b) { return a[key] > b[key] ? ad : -ad; };
var compDate = function(a, b) { return toUTC(a[key]) > toUTC(b[key]) ? ad : -ad; };
var toUTC = function(dateStr) { return Date.parse(dateStr.replace(/-/g, '/')); };
var compareFunc = [null, compNum, compStr, compDate][pat];
var sort = function(a, b) {
if (a[key] !== b[key]) {
return compareFunc(a, b);
} else {
//console.log('%csort!', 'background: cyan;', ad, key, a[key], b[key], a.id, b.id);
return a.id > b.id ? ad : -ad;
}
};
items = items.sort(sort);
return _.uniq(items, 'id');
};
};
initializeMylistSortV2();
if (conf.debugMode) {
require('watchapp/init/PopupMarqueeInitializer').popupMarqueeViewController.itemList.addEventListener('popup', function(body) {
console.log('%c popup: ' + body, 'background: #0ff');
});
console.log(JSON.parse($('#watchAPIDataContainer').text()));
//WindowUtil.shake = function() { console.log('%cshake', 'background: lightgreen;');};
}
}
// ?ref=等がついてるせいで未読既読のリンクの色が変わらなくなる問題の対策
// ShinjukuWatchと違いこっちはプレイリスト消えないモードがあるので、マイリスト等からの遷移でも遠慮無く全部消す
if (location.href.indexOf('?') >= 0) {
window.history.replaceState('', '', location.href.split('?')[0]);
}
function initTest(test) {
var console = window.console;
var expect = test.expect;
WatchApp.mixin(WatchItLater.test.spec, {
testChannelVideo: function(def) {
ChannelVideoList.load(function(r###lt) {
console.log('ChannelVideoList.load', r###lt);
expect(r###lt.name).toEqual('ニコニコアプリちゃんねるの動画', 'チャンネル名');
expect(r###lt.list.length >= 30).toBeTrue('2013/08/28時点で33件');
def.resolve();
}, {id: '55', ownerName: 'ニコニコアプリちゃんねる'});
},
testNewNicoSearch: function(def) {
var size = 15;
var search = new NewNicoSearch({});
search.load({query: 'vocaloid', size: size}, function(err, r###lt) {
console.log('testNewNicoSearch.load', err, r###lt);
expect(err).toBeNull('err === null');
expect(r###lt[0].dqnid)                 .toBeTruthy('先頭にdqnidが含まれる(なんの略?)');
expect(typeof r###lt[0].values[0].total).toEqual('number', 'ヒット件数');
expect(r###lt[0].values[0].service)     .toEqual('video',  '検索の種類');
expect(r###lt[1].type).toEqual('stats',  'type === stats'); // データの開始?
expect(r###lt[2].type           ).toEqual   ('hits',   'type === hits');
expect(r###lt[2].values         ).toBeTruthy('ヒットした内容');
expect(r###lt[2].values.length  ).toEqual   (size, 'sizeで指定した件数が返る');
expect(r###lt[2].values[0].cmsid).toBeTruthy('ヒットした内容にデータが含まれる');
expect(r###lt[3].type).toEqual('hits',  'type === stats'); // データの終了?
def.resolve();
});
},
testNewNicoSearchWrapperQuery: function(def) {
var wrapper = new NewNicoSearchWrapper({search: {}});
var params = {
searchWord: 'VOCALOID',
searchType: 'tag',
u: '1m',
l: 'short',
sort: 'l',
order: 'a',
page: 3
};
var query = wrapper._buildSearchQuery(params);
console.log(params, query);
expect(query.query).toEqual(params.searchWord,        '検索ワードのセット');
expect(query.from).toEqual(params.page * 32 - 32,    'ページ番号 -> fromの変換');
expect(query.sort_by).toEqual('length_seconds', 'l -> length_seconds');
expect(query.order).toEqual('asc',              'a -> asc');
// TODO:
expect(JSON.stringify(query.search).indexOf('["tags"]') >= 0).toBeTrue('タグ検索');
var filters = JSON.stringify(query.filters);
//console.log(filters);
expect(query.filters.length >= 2).toBeTrue('filters.lengthが2以上');
expect(filters.indexOf('"field":"start_time"') >= 0).toBeTrue('filtersにstart_timeが含まれる');
expect(filters.indexOf('"field":"length_seconds"') >= 0).toBeTrue('filtersにlength_secondsが含まれる');
def.resolve();
},
testNewNicoSearchWrapper: function(def) {
console.log('testNewNicoSearchWrapper');
var search = new NewNicoSearch({});
var wrapper = new NewNicoSearchWrapper({search: search});
wrapper.load({searchWord: 'ぬこぬこ動画', size: 100}, function(err, r###lt) {
console.log('testNewNicoSearchWrapper.load', err, r###lt);
expect(err).toBeNull('err === null');
expect(typeof r###lt.count).toEqual('number', '件数がnumber');
expect(r###lt.count > 0).toBeTrue('件数が入っている');
expect(r###lt.list.length).toBeTruthy('データが入っている');
expect(r###lt.list.length).toEqual(100, 'sizeで指定した件数が入っている');
expect(r###lt.list[0].type).toEqual(0, 'type === 0');
expect(/^\d+:\d+/.test(r###lt.list[0].length)).toBeTrue('動画長がmm:dd形式で入ってる');
def.resolve();
});
},
testNicoSearchRelatedTag: function(def) {
var related = new NicoSearchRelatedTag({});
related.load('voiceroid', function(err, r###lt) {
console.log('testNicoSearchRelatedTag.load', err, r###lt);
console.log(expect(err));
expect(err).toBeNull('err === null');
expect(r###lt.type).toEqual('tags', 'type === "tags"');
expect(r###lt.values).toBeTruthy('データが入っている');
expect(typeof r###lt.values[0]._rowid).toEqual('number', 'データに_rowidが入っている');
expect(typeof r###lt.values[0].tag)   .toEqual('string', 'データにtagが入っている');
def.resolve();
});
},
testSearchSuggest: function(def) {
var suggest = new NicoSearchSuggest({});
suggest.load('MMD', function(err, r###lt) {
console.log('testSearchSuggest.load', err, r###lt);
console.log(expect(err));
expect(err).toBeNull('err === null');
expect(r###lt.candidates).toBeTruthy('suggestの中身がある');
expect(r###lt.candidates.length).toBeTruthy('suggestのlengthがある');
def.resolve();
});
},
testUpdateMylistComment: function(def) {
// 一個以上マイリストがあって先頭のマイリストになにか登録されている必要がある
var Mylist = WatchItLater.mylist;
var randomMessage = 'RND: ' + Math.random();
var d = new $.Deferred();
d.promise()
.then(function() {
var d = new $.Deferred();
Mylist.loadMylistList(function(mylistList) {
expect(mylistList.length > 0).toBeTruthy('マイリスト一覧が1件以上');
console.log('先頭のマイリスト', mylistList[0].id, mylistList[0].name);
var groupId = mylistList[0].id;
if (mylistList.length <= 0) {
d.reject();
return;
}
d.resolve(groupId);
});
return d.promise();
})
.then(function(groupId) {
var d = new $.Deferred();
Mylist.reloadMylist(groupId, function(mylist) {
expect(mylist.length > 0).toBeTruthy('マイリストアイテムが一個以上');
var item = mylist[0];
var watchId = item.item_data.watch_id;
console.log('マイリスト先頭のアイテム', watchId, item.item_data.title);
d.resolve(watchId, groupId);
});
return d.promise();
})
.then(function(watchId, groupId) {
var d = new $.Deferred();
Mylist.updateMylistItem(watchId, groupId, function(r###lt) {
expect(r###lt).toEqual('ok', 'updateMylistItem() r###lt=ok');
d.resolve(watchId, groupId);
}, randomMessage);
return d.promise();
})
.then(Util.Deferred.wait(500))
.then(function(watchId, groupId) {
var d = new $.Deferred();
Mylist.reloadMylist(groupId, function(newlist) {
console.log('reloadMylist', groupId, newlist);
expect(newlist[0].description)
.toEqual(randomMessage, 'マイリストコメントが更新できている => ' + newlist[0].description);
d.resolve();
});
return d.promise();
}).then(function() {
def.resolve();
});
d.resolve();
},
testVideoRanking: function(def) {
VideoRanking.load(null, {id: -4000})
.then(function(r###lt) {
console.log('VideoRanking.load r###lt:', r###lt);
expect(r###lt.name).toEqual('カテゴリ合算', 'ダミーマイリストの名前が一致');
expect(r###lt.list.length).toEqual(300, 'カテゴリ合算ランキングは300件');
expect(r###lt.list[  0].title.indexOf('第001位')).toEqual(0,'ランキング1位のタイトル');
expect(r###lt.list[299].title.indexOf('第300位')).toEqual(0,'ランキング300位のタイトル');
def.resolve();
},
function() {
def.reject();
});
},
testNicorepoVideo: function(def) {
NicorepoVideo.loadAll(null, null)
.then(function(r###lt) {
console.log('NicorepoVideo.loadAll r###lt:', r###lt);
expect(r###lt.name).toEqual('【ニコレポ】すべての動画', 'ダミーマイリストの名前が一致');
expect(r###lt.list).toBeTruthy('ニコレポがある');
def.resolve();
},
function() {
def.reject();
});
},
testVideoInfoLoader: function(def) {
var loader = new VideoInfoLoader({});
$.when(
loader.load('sm9').then(function(r###lt) {
expect(r###lt.id).toEqual('sm9', '存在する動画ID');
expect(r###lt.length).toEqual('5:19', 'length');
return this.done();
}, function(err) {
return this.fail();
}),
loader.load('sm1').then(function(r###lt) {
return new $.Deferred().reject().promise();
}, function(resp) {
expect(resp.status).toEqual('fail', '存在しない動画ID');
return new $.Deferred().resolve().promise();
})
).then(function() { def.resolve(); }, function() { def.reject(); });
},
testRelatedVideo: function(def) {
var loader = new RelatedVideo({});
loader.load('sm9').then(function(r###lt) {
console.log('RelatedVideo', r###lt);
expect(r###lt.list).toBeTruthy('関連動画がある');
expect(r###lt.list[0].title).toBeTruthy('タイトルがある');
expect(r###lt.list[0].title.length >= 0).toBeTrue('タイトル長がある');
expect(typeof r###lt.list[0].type === 'number').toBeTrue('type属性がある');
def.resolve();
});
},
testVideoArray: function(def) {
window.WatchItLater.loader.videoArrayAPILoader.load(['sm9', 'sm13']).then(function(r###lt) {
console.log('VideoArrayAPILoader', r###lt);
expect(r###lt['sm9']).toBeTruthy('動画情報');
expect(r###lt['sm13'].title).toBeTruthy('タイトルがある');
expect(r###lt['sm13'].title.length >= 0).toBeTrue('タイトル長がある');
window.WatchItLater.loader.videoArrayAPILoader.load(['sm13', '1394785382']).then(function(r###lt) {
console.log('VideoArrayAPILoader', r###lt);
expect(r###lt['1394785382']).toBeTruthy('スレッドIDでも引ける');
expect(r###lt['1394785382'].title).toEqual('鬼灯の冷徹 第10話「十王の晩餐」「ダイエットは地獄みたいなもの」', '動画タイトル一致');
def.resolve();
});
});
},
testCeAPIVideoArray: function(def) {
window.WatchItLater.loader.ceAPIClient.videoArray(['sm9', 'sm13']).then(function(r###lt) {
console.log('ceAPIAPIClient.videoArray', r###lt);
expect(r###lt.status).toEqual('ok', 'status');
expect(r###lt.video_info).toBeTruthy('動画情報がある');
expect(r###lt.video_info[0].video.id).toEqual('sm9', '動画id');
def.resolve();
});
}
}); // end WatchApp.mixin
} // end initTest
window.console.time('init WatchItLater');
//    window.console.profile('init WatchItLater');
LocationHashParser.initialize();
initNews();
initShortcutKey();
initMouse();
initTouch();
initEvents();
initSearchContent($, conf, w);
initUserVideoContent($, conf, w);
initMylistContent($, conf, w);
initUploadedVideoContent($, conf, w);
initDeflistContent($, conf, w);
initVideoExplorer($, conf, w);
initRightPanel($, conf, w);
initLeftPanel($, conf, w);
initVideoReview($, conf, w);
initHidariue();
initVideoCounter();
initScreenMode();
initPlaylist($, conf, w);
initPageBottom($, conf, w);
initPageHeader($, conf, w);
initVideoTagContainer($, conf, w);
initNicoS($, conf, w);
initInvisibleCommentInput($, conf, w);
initOtherCss();
initCustomPlayerSize($, conf, w);
initStageVideo($, conf, w);
initHeatMap($, conf, w);
initPopupMarquee();
initMylistPanel($, conf, w);
initScroll($, conf, w);
initOther();
//    window.console.profileEnd('init WatchItLater');
window.console.timeEnd('init WatchItLater');
//    console.log('%cWatchItLater initialized!', 'background: lightgreen;');
onWindowResizeEnd();
if (conf.debugMode) {
initTest(WatchItLater.test);
}
define('WatchItLater', [], function() { return WatchItLater; });
};
if (window.WatchJsApi) {
require(
['WatchApp', 'watchapp/model/WatchInfoModel', 'prepareapp/PlayerStartupObserver'], function(WatchApp, WatchInfoModel, PlayerStartupObserver) {
var watchInfoModel = WatchInfoModel.getInstance();
if (watchInfoModel.initialized) {
window.WatchItLater.WatchController =
window.WatchController =
_watchController(window);
ZeroFunc(window);
} else {
var onReset = function() {
watchInfoModel.removeEventListener('reset', onReset);
window.setTimeout(function() {
window.WatchItLater.WatchController =
window.WatchController =
_watchController(window);
ZeroFunc(window);
}, 100);
};
watchInfoModel.addEventListener('reset', onReset);
if (conf.initializeImmediately) {
console.log('%cinitialize Immediately', 'background: lightgreen;');
//if (require.defined('playerPanel/view/ngPanel/NGGridProvider')) {
//  var ngg = require('playerPanel/view/ngPanel/NGGridProvider');
//  ngg.prototype._getList = function() {
//    return this._list || [];
//  };
//}
//var Nicoplayer = PlayerApp.ns.player.Nicoplayer;
var startup = function() {
startup = function() {};
if (PlayerStartupObserver._executed) {
return;
}
console.time('initialize Immediately');
PlayerStartupObserver._dispatch();
PlayerStartupObserver._executed = true;
console.timeEnd('initialize Immediately');
};
//          Nicoplayer.onCommentListInitialized(function() { startup(); });
window.setTimeout(startup, 0);
}
}
});
} else
if (location.host === 'www.nicovideo.jp' && location.pathname ==='/stamp') {
niconicodoRedirect();
}
/**
*  原宿プレイヤーでのあれこれ
*
*  マイリストパネルだけ追加
*
*/
(function() {
if (!w.Video) return;
if (!location.href.match(/\/watch\/(sm\d+|nm\d+|so\d+|\d+)/)) return;
var watchId = void 0, videoId = void 0;
if (w.Video === null) {
watchId = RegExp.$1;
w.Video = {id: watchId};
} else {
Video   = w.Video;
watchId = Video.v;
videoId = Video.id;
}
watchId = RegExp.$1;
var iframe = Mylist.getPanel('');
iframe.id = "mylist_add_frame";
iframe.setAttribute('style', 'position: fixed; right: 0; bottom: 0;');
document.body.appendChild(iframe);
iframe.watchId(watchId, videoId);
})();
/**
*  キーボードイベント他
*
*/
(function() {
w.document.body.addEventListener('keydown', function(e) {
if (e.keyCode === 27 || e.keyCode === 88) { // ESC or x
AnchorHoverPopup.hidePopup();
Popup.hide();
}
}, false);
w.document.body.addEventListener('click', function(e) {
var tagName = e.target.tagName, className = e.target.className;
//console.log(tagName, className);
if (tagName !== 'BUTTON' && tagName !== 'SELECT' && tagName !== 'OPTION' && className !== 'popupTagItem' && className.indexOf('mylistPopupPanel') < 0) {
AnchorHoverPopup.hidePopup();
}
}, false);
var touchInitialized = false;
TouchEventDispatcher.onflick(function(e) {
if (e.direction === 'right') {
if (!touchInitialized) {
document.getElementById('videoTagPopupContainer').className += ' w_touch';
touchInitialized = true;
}
}
}, false);
//    w.document.body.addEventListener('dblclick', function(e) {var tagName = e.target.tagName, className = e.target.className;console.log(tagName, className);});
})(w);
//===================================================
//===================================================
//===================================================
}); // end of monkey();
/**
* スマートフォン用APIを利用して動画情報を取得する Firefox + Greasemonkey用
*/
var spapi = function() {
if (window.name.indexOf('watchItLaterAPILoader') < 0 ) { return; }
var resp    = document.getElementsByTagName('nicovideo_video_response');
var session = location.hash.length > 1 ? location.hash.substr(1) : location.search;
var origin  = 'http://' + location.host.replace(/^.*?\./, 'www.');
var xml = '';
if (resp.length > 0) {
xml = resp[0].outerHTML;
}
try {
parent.postMessage(JSON.stringify({
id: 'WatchItLater',
type: 'VideoArrayAPILoader',
body: {
session: session,
xml: xml
}
}),
origin);
} catch (e) {
console.log('err', e);
}
};
/**
* Vita/3DS用APIを利用して情報を取得する Chrome + Tampermonkey用
* 参考: http://www59.atwiki.jp/nicoapi/pages/24.html
*/
var ceapi = function() {
if (window.name.indexOf('ceAPILoader') < 0 ) { return; }
var origin  = 'http://www.nicovideo.jp'; //'http://' + location.host.replace(/^.*?\./, 'www.');
var xmlHttpRequest = function(options) {
try {
var req = new XMLHttpRequest();
var method = options.method || 'GET';
req.onreadystatechange = function() {
if (req.readyState === 4) {
if (typeof options.onload === 'function') options.onload(req);
}
};
req.open(method, options.url, true);
if (options.headers) {
for (var h in options.headers) {
req.setRequestHeader(h, options.headers[h]);
}
}
req.send(options.data || null);
} catch (e) {
console.error(e);
}
};
window.addEventListener('message', function(event) {
var data = JSON.parse(event.data), timeoutTimer = null, isTimeout = false;
if (!data.url) { return; }
var sessionId = data.sessionId;
xmlHttpRequest({
url: data.url,
onload: function(resp) {
if (isTimeout) { return; }
else { window.clearTimeout(timeoutTimer); }
try {
parent.postMessage(JSON.stringify({
id: 'WatchItLater',
type: 'ceAPILoader',
body: {
sessionId: sessionId,
status: 'ok',
url: data.url,
body: resp.responseText
}
}),
origin);
} catch (e) {
console.log(
'%cError: parent.postMessage - ',
'color: red; background: yellow',
e, event.origin, event.data);
}
}
});
timeoutTimer = window.setTimeout(function() {
isTimeout = true;
parent.postMessage(JSON.stringify({
id: 'WatchItLater',
type: 'ceAPILoader',
body: {
sessionId: sessionId,
status: 'timeout',
url: data.url
}
}),
origin);
}, 30000);
});
try {
parent.postMessage(JSON.stringify({
id: 'WatchItLater',
type: 'ceAPILoader',
body: {
status: 'initialized'
}
}),
origin);
} catch (e) {
console.log('err', e);
}
};
try {
if (location.host === 'flapi.nicovideo.jp') {
return;
} else
if (location.host === 'i.nicovideo.jp') {
spapi();
} else
if (location.host === 'api.ce.nicovideo.jp') {
ceapi();
} else
if (location.host.indexOf('smile-') >= 0) {
return;
} else
if (location.host.indexOf('localhost.') === 0 || location.host.indexOf('www.') === 0) {
isNativeGM = false;
var inject = document.createElement('script');
inject.id = 'monkey';
inject.setAttribute('type', 'text/javascript');
inject.setAttribute('charset', 'UTF-8');
if (location.pathname.indexOf('/watch/') === 0) {
inject.appendChild(document.createTextNode(
'require(["WatchApp", "jquery", "lodash"], function() {' +
'console.log("%crequire WatchApp", "background: lightgreen;");' +
'(' + monkey + ')(false);' +
'});'
));
document.body.appendChild(inject);
} else {
inject.appendChild(document.createTextNode('(' + monkey + ')(false);'));
}
if (document.body) {
document.body.appendChild(inject);
} else {
document.documentElement.appendChild(inject);
}
} else {
monkey(false);
}
} catch(e) {
monkey(false);
}
})();