// ==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/*
// @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 GM_xmlhttpRequest
// @version 1.141121
// @downloadURL none
// ==/UserScript==
//
// * ver 1.140524
// * ver 1.140522
// - 本家のサムネイル仕様変更に対応
// * ver 1.140428
// - 本家の仕様変更で使えなくなっていた、プレイリストのブックマーク保存機能を復活
// * ver 1.140319
// - 謎の技術によって、ニコメンドがなくても説明文の動画リンクにサムネイルを出せるように
// - 細かなスタイル調整
// * ver 1.140303
// - 動画選択画面で再生リストの開閉が記憶されなくなったのに対抗
// - 動画切換え時に一番上までスクロールするようになったのに対抗
// - 本家の内部仕様変更(jQuery ver up等)に対応
// * ver 1.140227
// - タグ検索のソート順が毎回リセットされるようになったのに対抗
// * ver 1.140218
// - コメント重複を勝手に直してたけど不要になったので除去
// - 二本目以降の動画だけ自動再生を追加
// * ver 1.140207
// - テレビちゃんメニューの表示修正
// - スレッドIDのリンクからもタグを取得できるように(watchページ内のみ)
// - マイリスト選択メニュー部分の右クリックでとりマイの位置に戻る隠し機能
// * ver 1.140122
// - テレビちゃんメニューをShinjukuWatch仕様に
// * ver 1.140110
// - 検索フォームのオートコンプリートを調整
// - ニコメンドまわりのコード除去
// - 微妙にNicorenizerとの相性を改善
(function() {
var isNativeGM = true;
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 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: false,
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.GM_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) {
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;
}
*/}).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;
}
{* ページャーの字が小さくてクリックしにくいよね *}
#resultPagination {
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 .itemMylistComment {
font-size: 85%; color: #666; display: none;
color: #400; border: 1px solid #ccc; padding: 0 4px 0px; line-height: 130%; border-radius: 4px;
}
.column1 .itemMylistComment: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 .itemMylistComment {
color: #004;
}
.log-user-video-review .column1 .itemMylistComment:before {
content: 'レビュー ';
}
.column1 .itemMylistComment:after {
content: '';
}
.column1 .itemMylistComment pre {
font-family: inherit;
display: inline;
white-space: pre-wrap;
}
.videoExplorerContent .contentItemList .column1 .nicorepoOwnerIconContainer {
display: none;
}
.videoExplorerContent .contentItemList .nicorepoResult .column1 .nicorepoOwnerIconContainer {
float: right; display: block;
padding: 24px 14px 0 4px;
}
.videoExplorerContent .contentItemList .column1 .nicorepoOwnerIconContainer img {
height: 48px;
}
.videoExplorerBody.dummyMylist #searchResultContainer .favMylistEditContainer,
.videoExplorerBody.dummyMylist:not(.ranking) #searchResultMylistSortOptions,
.videoExplorerBody.dummyMylist .favMylistEditContainer,
.videoExplorerBody.dummyMylist:not(.ownerNicorepo) #searchResultHeader {
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 .nicorepoResult .itemVideoDescription, .videoExplorerContent .contentItemList .nicorepoResult .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.w_noNicoru .nicoru-button{
left: -9999; display: none !important;
}
body.w_noNicoru .menuOpened #videoMenuTopList li.videoMenuListNicoru .nicoru-button{
display: block !important;
}
body.w_noNicoru #videoTagContainer .tagInner #videoHeaderTagList li {
margin: 0 18px 4px 0;
}
body.w_noNicoru #videoTagContainer .tagInner #videoHeaderTagList li .tagControlContainer, body.w_noNicoru #videoTagContainer .tagInner #videoHeaderTagList li .tagControlEditContainer {
padding: 1px 0;
}
.userProfile.w_touch {
font-size: 150%; line-height: 120%;
}
.resultPagination.w_touch {
font-size: 200%;
}
.resultPagination.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 {
letter-spacing: -1px;
}
#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 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 *}
}
body:not(.full_with_browser) #content.w_compact.w_wide #videoTagContainer {
width: 1040px; {* base + 32 *}
}
body:not(.full_with_browser) #content.w_compact #videoTagContainer {
width: 948px; {* base - 60 *}
}
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;
}
#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;
}
{* body #videoHeader #videoMenuWrapper .defmylistButton, body #videoHeader #videoMenuWrapper .mylistButton {
display: none !important;
} *}
body #videoHeader #videoMenuTopList{
position: relative;
width: auto;
}
body #videoHeader.menuOpened #videoMenuWrapper .videoMenuList{
display: inline-block;
width: 60px;
min-height: 72px;
}
body #videoMenuTopList li.videoMenuListNicoru {
float: right;
min-height: 72px;
}
body #videoHeader.isAdult .videoMenuToggle, body #videoHeader.noAudioDownload .downloadButton {
display: inline-block;
opacity: 0.5;
pointer-events: none !important;
}
{* テレビちゃんメニューのスライド殺す *}
body #videoHeader.menuOpened #videoMenuWrapper {
margin-bottom: 0;
}
body #videoHeader.menuOpened #videoHeaderDetail {
margin-top: 8px;
}
.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: 'flatDesignMode',
// description: '軽い表示になります',
// values: {'なくす': 'on', 'なくさない': ''}},
{title: '「ニコる」をなくす', varName: 'noNicoru',
description: '画面上から見えなくなります。\nまた、コメントパネルの処理が軽くなります',
values: {'なくす': true, 'なくさない': false}},
{title: 'コメントパネルのマウスオーバー処理をなくす', varName: 'removeCommentPanelHoverEvent', reload: true,
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([
'
',
'
▲
WatchItLaterの設定 (※)のつく項目は、リロード後に反映されます',
'
'
].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 = $('');
} else {
$item = $('');
}
if ($ul) $inner.append($ul);
$ul =$('').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(''), self = this;
$panel.append($bottom);
$panel.find('.closeButton').click(function() {
self.close();
});
if ($shadow === null) {
$shadow = $('
');
}
}
};
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('' + title + '
');
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(' ');
var $chk = jQuery(' ');
$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('' + k + ' '));
$menu.append($label);
}
return $menu;
};
pt.createTextMenuItem = function(menu) {
var title = menu.title, varName = menu.varName;
var $menu = jQuery('' + title + '
');
if (menu.className) { $menu.addClass(menu.className);}
if (menu.description) { $menu.attr('title', menu.description); }
var currentValue = conf.getValue(varName);
var $input = jQuery(' ');
$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('' + title + '
');
var sel = [''], $sel;
for (var v = 48; v <= 90; v++) {
if (v >= 0x3c && v <= 0x3f) continue;
var c = String.fromCharCode(v);
var op = ['', c, ' ' ].join('');
sel.push(op);
}
sel.push(' ');
$sel = jQuery(sel.join(''));
var $meta = jQuery('有効 ctrl alt shift ').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(' ').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 result = JSON.parse(resp.responseText);
if (typeof callback === 'function') callback(result.status, result);
}
};
GM_xmlhttpRequest(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 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) {
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 = $('
タグ検索履歴 ');
$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(/&/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) + sortOrder;
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取得
GM_xmlhttpRequest({
url: url,
onload: function(resp) {
//console.log(116, resp.responseText);
var result = resp.responseText;
if (result.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.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';
GM_xmlhttpRequest({
url: url,
onload: function(resp) {
var result = JSON.parse(resp.responseText);
if (result.status === "ok" && result.mylistgroup) {
mylistlist = result.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';
GM_xmlhttpRequest({
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 result = JSON.parse(resp.responseText);
if (result.status === "ok" && result.mylistitem) {
defListItems = result.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;
GM_xmlhttpRequest({
url: url,
onload: function(resp) {
var result = JSON.parse(resp.responseText);
if (result.status === "ok" && result.mylistitem) {
mylistItems[groupId] = result.mylistitem;
if (typeof callback === "function") callback(result.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 result = JSON.parse(resp.responseText);
if (typeof callback === "function") callback(result.status, result);
if (jQuery) {
defListItems = jQuery.grep(defListItems, function(item) {
return item.item_data.watch_id !== watchId;
});
}
dispatchEvent('defMylistUpdate');
}
};
GM_xmlhttpRequest(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 result = JSON.parse(resp.responseText);
if (typeof callback === "function") callback(result.status, result, replaced);
}
};
GM_xmlhttpRequest(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 result = JSON.parse(resp.responseText);
if (typeof callback === "function") callback(result.status, result);
if (result.status === 'ok') {
dispatchEvent('mylistUpdate', {action: 'add', groupId: groupId, watchId: watchId});
EventDispatcher.dispatch('onMylistItemAdded', groupId, watchId);
self.clearMylistCache(groupId);
}
},
error: function() {
Popup.alert('ネットワークエラー');
}
};
GM_xmlhttpRequest(req);
};
// 普通のマイリストに入れたら、とりあえずマイリストからは削除(≒移動)
if (!this.deleteDefListItem(watchId, _add)) _add();
};
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 result = JSON.parse(resp.responseText);
if (result.status === 'ok') {
if (typeof callback === "function") callback(result.status, result);
dispatchEvent('mylistUpdate', {action: 'update', groupId: groupId, watchId: watchId});
EventDispatcher.dispatch('onMylistItemUpdated', groupId, watchId);
}
},
error: function() {
Popup.alert('ネットワークエラー');
}
};
GM_xmlhttpRequest(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 result = JSON.parse(resp.responseText);
if (result.status === 'ok') {
if (typeof callback === "function") callback(result.status, result);
dispatchEvent('mylistUpdate', {action: 'delete', groupId: groupId, watchId: watchId});
EventDispatcher.dispatch('onMylistItemDeleted', groupId, watchId);
}
},
error: function() {
Popup.alert('ネットワークエラー');
}
};
GM_xmlhttpRequest(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, result, replaced) {
self.reloadDefList();
if (status !== 'ok') {
Popup.alert('とりあえずマイリストへの登録に失敗: ' + result.error.description);
} else {
var torimai = 'とりあえずマイリスト ';
Popup.show(
torimai +
(replaced ? 'の先頭に移動しました' : 'に登録しました')
);
}
}, description);
};
var addMylist = function(watchId, mylistId, mylistName, description) {
self.addMylistItem(watchId, mylistId, function(status, result) {
self.reloadDefList();
if (status === 'ok') {
Popup.show( '' + mylistName + ' に登録しました');
} else {
Popup.alert(mylistName + 'への登録に失敗: ' + result.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 createSubmitButton() {
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, result) {
self.reloadDefList();
btn.style.display = 'none';
if (status !== "ok") {
Popup.alert('とりあえずマイリストから削除に失敗: ' + result.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 = createSubmitButton(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 = $([
'',
''].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([
'',
' ',
'',
name,
' ',
' ',
''].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('onMyMylistLoad', 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;
GM_xmlhttpRequest({
url: url,
onload: function(resp) {
var $result = $(resp.responseText).find('#favMylist');
if ($result.length >= 1) {
updateMaxPage($result);
if (page === 1) { favMylistList = []; }
$result.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($result) {
var $paging = $result.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(result) {
if (result.status !== 200) {
return;
}
try {
var json = JSON.parse(result.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]/, ' ');
require('watchapp/init/PopupMarqueeInitializer').popupMarqueeViewController.onData(
// Firefoxではflashの上に半透明要素を重ねられないのでとりあえず黒で塗りつぶす
'' + text + ' '
);
}
};
Popup.alert = function(text) {
console.log('%c' + text, 'background: yellow;');
if (w.WatchJsApi) {
text = text.replace(/[\n]/, ' ');
require('watchapp/init/PopupMarqueeInitializer').popupMarqueeViewController.onData(
'' + text + ' '
);
} 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 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) {
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 (this.href) 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();
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('' +
arguments[0] + ' ');
};
})();
//===================================================
//===================================================
//===================================================
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 = [], result = {}, def = new $.Deferred(), timeoutTimer = null;
initialize();
$(typeof watchId !== 'string' ? watchId : [watchId]).each(function(i, id) {
if (cacheData[id]) {
result[id] = cacheData[id];
} else {
ids.push(id);
}
});
ids = window._.unique(ids);
if (ids.length < 1) {
window.setTimeout(function() { def.resolve(result); }, 0);
return def;
}
var _ids = JSON.stringify(ids);
var onSuccess = function(infoList) {
$(ids).each(function(i, id) {
result[id] = result[id] || infoList[id] || cacheData[id];
});
window.clearTimeout(timeoutTimer);
currentRequestIds = ''; currentPromise = null;
def.resolve(result);
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) {
// 基本的に i.nicovideo.jpのほうが高機能だが、Chrome + Tampermonkeyからは使えないため回避策
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._.unique(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(result) {
try {
if (!format && format !== 'xml') {
result = JSON.parse(result).nicovideo_video_response;
result.status = result['@status'];
delete result['@status'];
}
} catch (e) {
console.log('%cJSON parse Error!', 'background: red;', e);
def.reject({});
}
return def.resolve(result);
}, 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 result = [];
for (var i = items.length - 1; i >= 0; i--) {
result.unshift(
videoExplorerController._item2playlistItem(items[i])
);
}
return result;
}
},
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);
},
appendSearchResultToPlaylist: 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, result, replaced) {
Mylist.reloadDefList();
if (status !== "ok") {
Popup.alert('とりあえずマイリストの登録に失敗: ' + result.error.description);
} else {
var torimai = 'とりあえずマイリスト ';
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);
};
},
commentPanelContextMenu: function() {
return function(a) {
a.preventDefault(); a.stopPropagation();
var c = this.commentListModel.getComment(this.parseResNo(jQuery(a.currentTarget)));
var WatchApp = null, WatchController = null;
if (c) {
var
$d = this.CommentContextMenu.$contextMenuContainer,
$e = jQuery("#playerCommentPanel"),
left = this.$commentTableHeaderOuter.position().left,
top = a.pageY - $e.offset().top,
f = Math.min($e.offset().top + $e.outerHeight(), jQuery(window).scrollTop() + jQuery(window).outerHeight());
if (f < a.pageY + $d.outerHeight()) top -= a.pageY + $d.outerHeight() - f;
this.CommentContextMenu.show(c, left, top);
}
};
}
};
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 $([
// '',
// '', title, ' ',
// ' ',
// ''].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 = $('▲ ');
// $history = $('');
// $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; }
};
// 偶数がascで奇数がdescかと思ったら特に統一されてなかった
if (
sortKey === 'first_retrieve' ||
sortKey === 'thread_update_time'
) {
order = (sortId % 2 === 1) ? 'asc' : 'desc';
} 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.sort(compare[order]);
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(result) {
console.log('result', result);
if (result.status !== 200) {
callback('fail', 'HTTP status:' + result.status);
return;
}
var data;
try {
var lines = result.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, result);
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' // 並び順指定なし
},
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 (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, result) {
this.onLoad(err, result, params, query, callback);
}, this));
},
onLoad: function(err, result, params, query, callback) {
if (err) {
console.log('load fail', err, result);
callback('fail', {message: '通信に失敗しました1'});
return;
}
var searchResult;
searchResult = {
status: 'ok',
count: result[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;
}
}
searchResult.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
});
}
};
for (var i = 1; i < result.length; i++) {
if (result[i].type === 'hits' && result[i].endofstream) { break; }
if (result[i].type === 'hits' && result[i].values) {
pushItems(result[i].values);
}
}
callback(null, searchResult);
}
};
// 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',
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: 'POST',
data: word,
timeout: 30000,
complete: function(result) {
if (result.status !== 200) {
callback('fail', 'HTTP status:' + result.status);
return;
}
var data;
try {
data = JSON.parse(result.responseText);
} catch(e) {
console.log('Exception: ', e, result);
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(result) {
if (result.status !== 200) {
callback('fail', 'HTTP status:' + result.status);
return;
}
var data;
try {
var lines = result.responseText.split('\n');
data = JSON.parse(lines[0]);
} catch(e) {
console.log('Exception: ', e, result);
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(result) {
if (result.suggest_video && result.suggest_video.id) {
if (typeof callback === 'function') { callback(null, result.suggest_video); }
def.resolve(Util.Cache.set(cache_key, result.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();
}
};
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, result) {
if (err !== null) {
return def.reject({message: '通信に失敗しました(1)', status: 'fail', err: err});
}
return def.resolve(result);
}
);
return def.promise();
}
};
WatchItLater.RelatedVideo = new RelatedVideo({});
/**
* 動画視聴履歴をマイリストAPIと互換のある形式で返すことで、ダミーマイリストとして表示してしまう作戦
*/
var VideoWatchHistory = (function(w, Util){
function load(callback) {
var $, myNick, myId, url;
try{
$ = w.$; url = '/my/history';
myNick = WatchController.getMyNick(); myId = 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 result = new DummyMylist({
id: '-1',
sort: '1',
name: myNick + 'の視聴履歴',
user_id: myId,
user_name: 'ニコニコ動画'
});
GM_xmlhttpRequest({
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()
});
result.push(item);
});
callback(Util.Cache.set(CACHE_KEY, result, 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 result = new DummyMylist({
id: '-2',
sort: '1',
name: 'あなたにオススメの動画'
});
GM_xmlhttpRequest({
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) {
result.unshift(histories[v]);
}
result.slice(0, 128);
callback(Util.Cache.set(CACHE_KEY, result, CACHE_TIME));
},
onerror: function() {
throw { message: '取得に失敗しました', status: 'fail'};
}
});
}
function load(callback, param) {
request(function(result) {
var viewPage = (param && typeof param.page === 'number') ? param.page : 1;
result.setPage(viewPage);
callback(result);
});
}
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-src'),
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-src'),
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, result, nextLink, type) {
var def = new $.Deferred();
if (nextLink === null) {
return def.resolve(baseUrl, result, 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() {
result.push(parseNicorepoItem(this));
});
var nextLinkReg = /(last_timeline|offset)=(\d+)/;
if (hasNextPage) {
var href = $nextPageLink.attr('href');
if (nextLinkReg.test(href)) {
def.resolve(baseUrl, result, RegExp.$2, RegExp.$1);
} else {
def.resolve(baseUrl, result, null, null);
}
} else {
def.resolve(baseUrl, result, null, null);
}
},
function() {
def.reject();
});
return def.promise();
};
var pipeRequest = function(baseUrl, result, 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 = result.rawData.list.length - 1; i >= 0; i--) {
var item = result.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]);
}
result.rawData.list = uniq_items;
callback(result);
}
);
def.resolve(baseUrl, result, '', '');
};
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
result = 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, result, 2, function(result) {
def.resolve(Util.Cache.set(baseUrl, result, CACHE_TIME));
});
return def.promise();
};
var load = function(callback, param) {
return request(param)
.then(function(result) {
var viewPage = (param && typeof param.page === 'number') ? param.page : 1;
result.sortItem(param.sort || 1, true);
result.setPage(viewPage);
if (typeof result === 'function') { callback(result); }
return this.done(result);
}, 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'),
result = 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)
});
result.push(item);
});
return result;
};
var parseRssItem = function($item) {
var
desc_cdata = $item.find('description').text(),
$desc = $('' + desc_cdata + '
');
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, result, page, maxPage) {
var def = new $.Deferred(), p = def.promise();
var getPipe = function(result, 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++) {
result.push(res.rawData.list[i]);
}
});
};
};
for (var i = page; i <= maxPage; i++) {
p = p.then(getPipe(result, 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 result = new DummyMylist({
name: '総合ランキング',
id: '-100'
});
pipeRequest(baseUrl, result, page, maxPage).then(
function() {
def.resolve(Util.Cache.set(baseUrl, result, 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(result) {
result.name = p.genreName;
result.setPage(p.viewPage);
this.done(result);
});
};
var load = function(onload, param) {
var p = parseParam(param);
return request(p.baseUrl, 1, p.maxRssPage)
.then(function(result) {
result.name = p.genreName;
result.setPage(p.viewPage);
if (typeof onload === 'function') {
onload(result);
}
return this.done(result);
}, 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 * 1, MAX_PAGE = 3,
getPipe = function(baseUrl, result, 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, result);
def.resolve(hasNextPage);
}, function(err) {
def.reject(err);
});
return def.promise();
};
},
pipeRequest = function(baseUrl, result) {
var def = new $.Deferred(), p = def.promise();
var maxPage = MAX_PAGE;
for (var i = 1; i <= maxPage; i++) {
p = p.then(getPipe(baseUrl, result, i));
if (i < maxPage) { p = p.then(Util.Deferred.wait(300)); }
}
p.then(function() {
this.done(result);
});
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 = 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);
}
return def.resolve(cacheData);
}
var result = new DummyMylist({
id: 'ch' + id,
sort: '1',
name: ownerName + 'の動画',
user_id: myId,
user_name: 'ニコニコ動画'
});
pipeRequest(url, result).then(function() {
Util.Cache.set(CACHE_KEY, result, CACHE_TIME);
if (typeof callback === 'function') callback(result);
def.resolve(result);
});
return def.promise();
},
parseItems = function(html, result) {
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;
result.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 (!WatchController.isChannelVideo()) {
throw {message: 'チャンネル情報の取得に失敗しました', status: 'fail'};
}
var params = {
id: WatchController.getOwnerId(),
ownerName: WatchController.getOwnerName()
};
var def = new $.Deferred();
load(callback, params).then(function(result) {
if (typeof callback === 'function') callback(result);
def.resolve(result);
}, function() {
def.reject({message: 'チャンネル動画の取得に失敗しました', status: 'fail'});
});
return def.promise();
};
var self = {
load: load,
loadOwnerVideo: loadOwnerVideo
};
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);
};
/**
* 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 = $('
');
$button = $('yu ').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 = $(
'再生: コメ: マイ: '
);
assignVideoCountToDom($tpl, counter);
if ((conf.popupViewCounter === 'always') ||
(conf.popupViewCounter === 'full' && $('body').hasClass('full_with_browser'))
) {
Popup.show(
$('
')
.append(
$(' ')
.text(window._.unescape(title))
.attr('href', 'http://nico.ms/' + watchId)
)
.html() +
''+ $tpl.html() + ' '
);
}
$('#fullScreenToggleContainer').html([
' ',
'', title, '
',
'',$('.videoPostedAt:last').text(), '
',
'', $tpl.html(), '
',
''].join(''))
.toggleClass('favorite', WatchController.isFavoriteOwner())
.find('img').attr('title', WatchController.getOwnerName());
if (conf.headerViewCounter) {
var vc = $('#videoCounter');
if (vc.length < 1) {
var 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 = $([
'',
'
',
'
',
'
',
' ',
'
提供: ',
' ',
'',
'
',
'
',
' ',
'
投稿者: ',
' ',
' ',
' ',
'
',
'
',
'
',
'
',
'
',
'再生: ',
'コメント: ',
'マイリスト: ',
' ',
'
',
'
',
'
',
'
',
'
',
'
',
''].join(''));
// - 左パネル乗っ取る
function initLeftPanel($, conf, w) {
var $tab = $([
''].join(''));
var
$sidePanel = $('
').addClass('sidePanel'),
$infoPanel = $('
').attr({'id': 'leftVideoInfo', 'class': 'sideVideoInfo sidePanelInner'}),
$ichibaPanel = $('
').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 = $([
'NG共有: ',
'',
'高 ',
'中 ',
'低 ',
'無 ',
' ',
'
',
''].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(); }
});
if (conf.removeCommentPanelHoverEvent) {
$("#commentDefault").find(".commentTableContainerInner") .off('mouseover').off('mouseenter').off('mouseleave').off('mouseout');
$('#playerCommentPanel .section .commentTable .commentTableContainer') .off('mouseover').off('mouseenter').off('mouseleave').off('mouseout');
PlayerInitializer.commentPanelViewController.commentContent.$commentTableContainer
.off('contextmenu')
.on('contextmenu', '.cell',
$.proxy(Util.Closure.commentPanelContextMenu(), PlayerInitializer.commentPanelViewController.commentContent)
);
}
EventDispatcher.addEventListener('onVideoChangeStatusUpdated', function(isChanging) {
if (isChanging) {
PlayerInitializer.commentPanelViewController.commentContent.$commentTableContainer
.find('.cell').off();
}
});
} // end initRightPanel
function initRightPanelHorizontalTab($, conf, w) {
} //
function initRightPanelVerticalTab($sidePanel) {
if (!conf.rightPanelJack) { return; }
var PlayerInitializer = require('watchapp/init/PlayerInitializer');
var $tab = $([
'',
'',
'動画情報 ',
'ニコニコ市場 ',
'レビュー ',
' '].join(''));
var $infoPanel = $('
').attr({'id': 'rightVideoInfo', 'class': 'sideVideoInfo sidePanelInner'});
var $ichibaPanel = $('
').attr({'id': 'rightIchibaPanel', 'class': 'sideIchibaPanel sidePanelInner'});
var $reviewPanel = $('
').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() {
PlayerInitializer.commentPanelViewController.contentManager.activeContent().refresh();
}, 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 = $([
'
',
''].join(''));
var $nextButton = $([
'次に再生
',
''].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 = $([
'',
'
',
'
',
''].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 '' + addComma(s) + ' ';
};
var onWatchIdInfoReady = function(result) {
$(watchLinks).each(function(i, watchLink) {
var id = watchLink.id, $target = watchLink.$target;
if (result[id]) {
var info = result[id];
var $thmb = $([
'',
'
',
'
', info.first_retrieve ,' 投稿 ',
'
', info.title, ' (', info.length, ')
',
'
',
'再生: ', ac(info.view_counter) ,' ',
' ',
'マイ: ', ac(info.mylist_counter),' ',
'
',
'
'].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 = //, links = [], n;
html = html.split(' ').join(' ');
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, '$1 ');
for (var i = 0, len = links.length; i < len; i++) {
html = html.replace(' ', links[i]);
}
html = html.split(' ').join(' ');
var $description = $('' + html + '
');
bindDescriptionEvents($description);
decorateVideoDescriptionLink($description);
return $description;
} //
function resetSideIchibaPanel($ichibaPanel, force) {
$ichibaPanel.scrollTop(0).find('*').unbind().empty();
var $inner = $('
');
var $header = $('');
$inner.append($header);
var items = [];
$('#ichibaMain').find('.ichiba_mainitem>div').each(function() {
var $item = $(this).clone().attr('id', null);
var $dl = $(' ').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');
}
}
$inner.find('.nicoru').remove();
var $footer = $('');
var $addIchiba = $('商品を貼る ');
$addIchiba.click(function() {
AnchorHoverPopup.hidePopup();
ichibaSearch();
});
$footer.append($addIchiba);
var $reloadIchiba = $('リロード ');
$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(' \ │ / /‾\ /‾‾‾‾‾‾‾‾‾ ─( ゜ ∀ ゜ )< しんねんしんねん! \_/ \_________ / │ \ ');
// }
if (!conf.hidariue) { return; }
if (!hidariue) {
$('#videoMenuTopList').append('
');
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 = function(title, titleLink) {
this.initializeBaseDom(title, titleLink);
};
WatchApp.mixin(VideoExplorerToggleMenu.prototype, {
initializeBaseDom: function(title, titleLink) {
this._$toggle = $('');
this._$menu = $('');
this._$list = this._$menu.find('ul');
var $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) {
var
$a = $(' ')
.attr(attr)
.text(title),
$li = $(' ').addClass(iconType);
$li.append($a);
this._$list.append($li);
return $a;
},
addMylistItem: function(name, mylistId, title, iconType) {
var
$a = $(' ')
.text(name)
.attr({
href: '/mylist/' + mylistId,
title: title,
'data-menu-type': 'mylist',
'data-mylist-id': mylistId,
}),
$li = $(' ').addClass(iconType || '');
$li.append($a);
this._$list.append($li);
return $a;
},
show: function() {
this._$toggle.fadeIn(500);
}
});
WatchItLater.videoExplorerMenu = {};
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 = $(' '),
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 = $(' '),
$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(
$(' ').append(
$(' ')
.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 =
$(' ')
.attr({
href: '/ranking/fav/' + term + '/' + genre,
'data-menu-type': 'mylist',
'data-mylist-id': id
})
.text(name)
.addClass(genre);
var $li = $(' ');
if (genre === category) {
$li.addClass('isCategory'); // nameと同じならカテゴリランキング、違うならジャンルランキング
if (genre !== 'all' && genre !== 'g_politics' && genre !== 'r18') {
var $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, result) {
if (status === 'ok') {
if (this._type === 'deflist') {
WatchController.clearDeflistCache();
}
} else {
Popup.alert('更新に失敗: ' + result.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 = $(' ').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('');
tmp.push(list[i].title); // 既にエスケープされてる
tmp.push(' ');
}
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) {
return str.replace(/[A-Za-z0-9]/g, 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 result = true, i = func.length, f;
while (--i >= 0 && (result || isInvert)) {
f = func[i];
result &= f(item);
}
return isInvert ? !result : result;
};
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: $([
'',
'
',
'
',
'
この動画はリストに登録されています ',
'
この動画はリストにありません ',
'
',
'登録 ',
'外す ',
' ',
'
',
''].join(''))
});
var grepOptionView = new GrepOptionView({
content: content,
listName: 'suggestMylistTitle',
$view: $([
'',
'',
'
',
].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);
content.clear_org = content.clear;
content.clear = $.proxy(function() {
this.setFilter(null);
this.clear_org();
grepOptionView.clear();
}, content);
content.getNickname = $.proxy(function() {
if (this._nickname && this._nickname.length > 0) {
return this._nickname;
}
return 'no-name';
}, content);
content.onLoad_org = content.onLoad;
content.onLoad = $.proxy(function(err, result) {
this._isOwnerNicorepo = result.isOwnerNicorepo;
this._isRanking = result.isRanking;
var filter = this.getFilter();
if (err === null && result.list && result.list.length) {
if (!result.rawList) result.rawList = result.list.concat();
if (filter) {
var list = [];
for (var i = result.rawList.length - 1; i >= 0; i--) {
var item = result.rawList[i];
if (item.title && filter(item)) {
list.unshift(item);
}
}
result.list = list;
} else {
result.list = result.rawList.concat();
}
} else
if (result.rawList) {
result.list = result.rawList.concat();
}
this._rawList = result.rawList || [];
this.onLoad_org(err, result);
if (this.getIsMine()) {
EventDispatcher.dispatch('onMyMylistLoad', this.getMylistId(), {
name: this.getName(),
items: result.rawList
});
}
}, 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);
loader.load_org = loader.load;
loader.load = $.proxy(function(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, result) {
result.isOwnerNicorepo = isOwnerNicorepo;
result.isRanking = isRanking;
callback(err, result);
};
if (id < 0) {
var timeoutTimer = null;
var onload = function(result) {
window.clearTimeout(timeoutTimer);
// 投稿者ニコレポが0件で、投稿動画一覧を公開していたらそっちを開くタイマーをセット
if (result.list.length < 1 &&
parseInt(id, 10) === NicorepoVideo.REPO_OWNER &&
WatchController.isVideoPublic()) {
window.setTimeout(function() {
WatchController.openVideoOwnersVideo();
}, 500);
}
applyFilter(null, result);
};
var onerror = function(result) {
window.clearTimeout(timeoutTimer);
callback('error', result);
};
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'});
}
}
} else {
this.load_org(params, applyFilter);
}
}, loader);
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');
MylistDetailView.prototype.update_org = MylistDetailView.prototype.update;
MylistDetailView.prototype.update = function(id, name, description, count) {
this.update_org(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())
;
};
proto.detach_org = proto.detach || function() {};
proto.detach = function() {
this.detach_org();
watchingVideoView.detach();
grepOptionView.detach();
};
proto.onUpdate_org = proto.onUpdate || function() {};
proto.onUpdate = function() {
this.onUpdate_org();
updateCssClass(this._content);
watchingVideoView.update();
grepOptionView.update();
this._$content.find('.mylistSortOrder').before(watchingVideoView.getView());
this._$content.find('.mylistSortOrder').before(grepOptionView.getView());
};
proto.onError_org = proto.onError || function() {};
proto.onError = function() {
this.onError_org();
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: $([
'',
'
',
'
',
'
この動画はリストに登録されています ',
'
この動画はリストにありません ',
'
',
'登録 ',
'外す ',
' ',
'
',
''].join(''))
});
var grepOptionView = new GrepOptionView({
content: content,
listName: 'suggestDeflistTitle',
$view: $([
'',
'',
'
',
].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, result) {
var filter = this.getFilter();
if (err === null && result.list && result.list.length) {
if (!result.rawList) result.rawList = result.list.concat();
if (filter) {
var list = [];
for (var i = result.rawList.length - 1; i >= 0; i--) {
var item = result.rawList[i];
if (item.title && filter(item)) {
list.unshift(item);
}
}
result.list = list;
} else {
result.list = result.rawList.concat();
}
} else
if (result.rawList) {
result.list = result.rawList.concat();
}
this._rawList = result.rawList || [];
this.onLoad_org(err, result);
}, 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 = [
'',
''].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();
}, 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 = [//'