archive.is webpage capture | からアーカイブ | 2015年10月15日 15:20:39 UTC | |
| 原本 | 2015年10月12日 06:36:19 UTC | ||
| すべてのスクリーンショット, | ドメインから gist.github.com ドメインから webcache.googleusercontent.com | ||
| ウェブページスクリーンショット | |||
short link long link html code wiki code | |||
attr(aria-label)| // ==UserScript== | |
| // @name kusa5 | |
| // @namespace net.buhoho.kusa5 | |
| // @include http://www.nicovideo.jp/watch/* | |
| // @version 1 | |
| // @grant none | |
| // @description ニコ動html5表示 | |
| // ==/UserScript== | |
| //localStorage.kusa5buffer : trueにするとバッファリングするようになる | |
| //localStorage.kusa5disableAutoplay : trueにすると自動再生しない | |
| //開発ツールのコンソールにて | |
| //localStorage.kusa5buffer = true; | |
| //みたいに打ち込んで設定する | |
| 'use strict'; | |
| $('.playerContainer').hide(); | |
| //$('#playlist').hide(); //お好み | |
| $('#playerContainerSlideArea').attr('id', 'kusa5'); | |
| $('#playerContainerWrapper').insertBefore('.videoHeaderOuter'); // お好み | |
| $(".notify_update_flash_player").hide(); //Flash未インストール警告 | |
| const OPT = { | |
| buffer: localStorage.kusa5buffer, // たぶんfirefoxじゃないと正常に動かない | |
| debug: false | |
| }; | |
| const ASKURL = 'http://flapi.nicovideo.jp/api/getflv?v='; | |
| const THUMB = 'http://tn-skr3.smilevideo.jp/smile?i='; | |
| const WATCH = 'http://www.nicovideo.jp/watch/'; | |
| const apidata = JSON.parse($('#watchAPIDataContainer').text()); | |
| const launchID = apidata.videoDetail.v; | |
| const isIframe = window != parent; | |
| const ICON = "https://cdnjs.cloudflare.com/ajax/libs/foundicons/3.0.0/svgs/"; | |
| addGlobalStyle(` | |
| #kusa5 { | |
| position: relative; | |
| /*background-color: hsla(180, 10%, 0%, 0.8);*/ | |
| background-color: #000; | |
| width: 640px; | |
| height: 360px; | |
| overflow: hidden; | |
| margin: 0 auto; | |
| } | |
| #kusa5 video { | |
| display: block; | |
| background-color: #000; | |
| height: 720px; | |
| max-width: 100%; /* 画面外にはみ出ないように */ | |
| margin: 0 auto; | |
| } | |
| #wallImageContainer .wallImageCenteringArea .wallAlignmentArea.image2{ | |
| z-index: 3; | |
| background-color: #CCCEC3; | |
| /* | |
| background-image: url('${ THUMB + launchID }'); | |
| filter: contrast(0.25) opacity(.25); | |
| -webkit-filter: contrast(0.25) opacity(.25); | |
| */ | |
| } | |
| #playerContainerWrapper { | |
| padding: 60px 0; | |
| } | |
| /* | |
| コントロールパネル関係 | |
| ******************************************************************************/ | |
| .controle-panel { | |
| z-index: 10; /* コメントより手前 */ | |
| color: rgba(255, 255, 255, 0.87); | |
| text-shadow: 2px 1px #000; | |
| position:absolute; | |
| bottom: 0; | |
| width: 100%; | |
| background: #0C2529; | |
| transition: transform .2s; | |
| /* transform: translate3d(0, 47px, 0); */ | |
| overflow: hidden; | |
| cursor: default; | |
| height: 50px; | |
| } | |
| #kusa5:hover .controle-panel { | |
| transform: translate3d(0, 0, 0); | |
| } | |
| .controle-panel .btn, | |
| input+label { | |
| color: rgba(255, 255, 255, 0.87); | |
| font-size: 18px; | |
| border: none; | |
| background-color: transparent; | |
| } | |
| .controle-panel .r {float: right;} | |
| .controle-panel .progressBar { | |
| cursor: pointer; | |
| position: relative; | |
| height: 14px; | |
| background-color: rgba(255, 255, 255, 0.24); | |
| width: 100%; | |
| } | |
| .controle-panel .progressBar span { | |
| position: absolute;; | |
| top: 0; | |
| left: 0; | |
| width: 0; | |
| height: 100%; | |
| } | |
| .controle-panel .progressBar.seek .mainbar { | |
| background-color: #8CD6E7; | |
| } | |
| .controle-panel .progressBar.seek .bufferbar { | |
| background-color: rgba(168, 191, 210, 0.37); | |
| } | |
| .controle-panel .progressBar.buf { height: 2px;} | |
| .controle-panel .progressBar.buf .bar { background-color: #D736A2} | |
| button.btn.ico { | |
| color: #000; | |
| position: relative; | |
| background-repeat: no-repeat; | |
| background-size: contain; | |
| filter: invert(1) opacity(0.8); | |
| -webkit-filter: invert(1) opacity(0.8); | |
| width: 25px; | |
| height: 25px; | |
| background-size: 18px; | |
| background-position: 5px; | |
| margin: 4px 5px; | |
| cursor: pointer; | |
| } | |
| button.btn.ico:hover { | |
| filter: invert(1) opacity(1); | |
| -webkit-filter: invert(1) opacity(1); | |
| } | |
| button.btn.ico.play { | |
| background-image: url("${ICON}fi-play.svg"); | |
| } | |
| #kusa5.playing button.btn.ico.play { | |
| /* 再生中 */ | |
| background-image: url("${ICON}fi-pause.svg"); | |
| } | |
| button.btn.ico:active { | |
| transform: scale(0.9); | |
| } | |
| button.btn.ico.volumedown { | |
| background-image: url("${ICON}fi-volume-none.svg"); | |
| } | |
| button.btn.ico.volumeup { | |
| background-image: url("${ICON}fi-volume.svg"); | |
| } | |
| button.btn.volume > span.volume-num { | |
| font-size: 10px; | |
| position: absolute; | |
| top: 0; | |
| right: -8px; | |
| } | |
| button.btn.ico.full { | |
| background-image: url("${ICON}fi-arrows-expand.svg"); | |
| } | |
| #kusa5:-moz-full-screen button.btn.ico.full { | |
| background-image: url("${ICON}fi-arrows-compress.svg"); | |
| } | |
| #kusa5:-webkit-full-screen button.btn.ico.full { | |
| background-image: url("${ICON}fi-arrows-compress.svg"); | |
| } | |
| .controle-panel .playtime { | |
| line-height: 32px; | |
| } | |
| button.btn.ico.comment-hidden { | |
| background-image: url(https://cdnjs.cloudflare.com/ajax/libs/topcoat-icons/0.1.0/svg/chat.svg); | |
| } | |
| /* 非表示状態 */ | |
| #kusa5.comment-hidden .msg { opacity: 0;} | |
| button.comment-hidden { | |
| opacity: 1; | |
| } | |
| #kusa5.comment-hidden button.comment-hidden { | |
| opacity: 0.5; | |
| } | |
| input.btn { | |
| display: none; | |
| } | |
| input.btn+label { | |
| color: #999; | |
| display: inline-block; | |
| background-color: hsla(0. 0%, 0%, 0.3); | |
| text-align: center; | |
| } | |
| input.btn+label:hover, | |
| input.btn:checked+label { | |
| color: #fff; | |
| text-decoration-line: underline; | |
| } | |
| input.btn+label span{ | |
| font-size:0.5em; | |
| } | |
| div.ratepanel { | |
| display: inline-block; | |
| text-align: center; | |
| } | |
| /* | |
| コメント要素関連 | |
| ******************************************************************************/ | |
| #kusa5 .msg { | |
| z-index: 5; | |
| display: inline-block; | |
| word-break: keep-all; | |
| font-size: 1.8em; | |
| color: white; | |
| padding: 0 .5em; | |
| position: absolute; | |
| transition-duration: 6s; | |
| transition-timing-function: linear; | |
| transition-property: transform; | |
| transform: translate3d(105% ,0,0); /* 画面外に配置するので */ | |
| text-shadow: | |
| 0px 0.05em 1px #222, | |
| 0.05em 0px 1px #222, | |
| 0px -0.05em 1px #222, | |
| -0.05em 0px 1px #444; | |
| top: 0; | |
| } | |
| #kusa5 .msg.l1 { top: calc(1.4em * 0);} | |
| #kusa5 .msg.l2 { top: calc(1.4em * 1);} | |
| #kusa5 .msg.l3 { top: calc(1.4em * 2);} | |
| #kusa5 .msg.l4 { top: calc(1.4em * 3);} | |
| #kusa5 .msg.l5 { top: calc(1.4em * 4);} | |
| #kusa5 .msg.l6 { top: calc(1.4em * 5);} | |
| #kusa5 .msg.l7 { top: calc(1.4em * 6);} | |
| #kusa5 .msg.l8 { top: calc(1.4em * 7);} | |
| #kusa5 .msg.l9 { top: calc(1.4em * 8);} | |
| #kusa5 .msg.l10 { top: calc(1.4em * 9);} | |
| #kusa5 .msg.l11 { top: calc(1.4em * 10);} | |
| #kusa5 .msg.l12 { top: calc(1.4em * 11);} | |
| #kusa5 .msg.l13 { top: calc(1.4em * 12);} | |
| /* | |
| フルスクリーン関連 | |
| ******************************************************************************/ | |
| /* 何故か一つづつfont-size指定しないと効かない */ | |
| #kusa5:-moz-full-screen .msg {font-size: 3.5em; } | |
| #kusa5:-webkit-full-screen .msg {font-size: 3.5em; } | |
| #kusa5:-webkit-full-screen { | |
| width: 100%; | |
| height: 100%; | |
| } | |
| /* | |
| 左上に縮小表示中 | |
| ******************************************************************************/ | |
| body.size_small.no_setting_panel.videoExplorer #kusa5 { | |
| height: 100%; | |
| width: 100%; | |
| margin: 0; | |
| } | |
| body.size_small.no_setting_panel.videoExplorer #kusa5 .msg{ | |
| font-size: 12px; | |
| } | |
| @media (max-width: 1399px) and (min-width: 1140px) { | |
| #kusa5 { width: 854px; height: 480px; } | |
| #kusa5 .msg{ font-size: 2.0em; } | |
| } | |
| /** 大画面向け */ | |
| @media (min-width: 1400px) { | |
| #kusa5 { width: 1280px; height: 770px; } | |
| #kusa5 .msg{ font-size: 2.8em; } | |
| } | |
| `); | |
| const $video = $(`<video type="video/mp4"' | |
| codecs="avc1.42E01E, mp4a.40.2" | |
| autoplay />`) | |
| .on('ended', buffShift) | |
| .on('pause', ev => { | |
| $("#kusa5").removeClass("playing"); | |
| localStorage.nicoRate = ev.target.playbackRate; | |
| }) | |
| .on('play', ev => { | |
| $("#kusa5").addClass("playing"); | |
| // レート情報の記憶 | |
| $('input[value="'+ localStorage.nicoRate +'"]').click(); | |
| ev.target.playbackRate = localStorage.nicoRate; | |
| ev.target.volume = localStorage.nicoVolume * 0.2; | |
| if (!isIframe) | |
| return; | |
| // バッファー再生用のプレーヤーは処理を重くしないためにrata1 | |
| ev.target.playbackRate = 1; | |
| $(ev.target).off().prop('muted', true); | |
| }); | |
| if (localStorage.kusa5disableAutoplay === "true") | |
| $video.removeAttr('autoplay'); | |
| $video.videoToggle = function() { | |
| var v = $video[0]; | |
| v.paused ? v.play() : v.pause(); | |
| }; | |
| $video.click($video.videoToggle); | |
| function addGlobalStyle(css) { | |
| var styleSeet = $('<style type="text/css">'); | |
| styleSeet.text(css); | |
| $('head').append(styleSeet); | |
| } | |
| /* 現在のページのDOMから次動画のIDを取得する。 | |
| * なので次の次の動画のIDを取るなら事前にヘッダーを書き換えておく必要がある。 | |
| */ | |
| function getNextId() { | |
| const currentID = $('#kusa5 video').data('smid'); | |
| const id = /\W?(s[mo]\d{3,10})\W?/.source; // 現状見受けられる動画は8桁 | |
| const next = "(?:" + ["次","next","つづ","続","最","終"] | |
| .map(s => s + ".{0,4}") | |
| .join("|") + ")"; | |
| //const prev = ["前","prev","まえ","ぜん","一","初"]; | |
| // スペースに使われそうな文字(出現しないかもしれない) | |
| const s = /[\s_|::]?/.source; | |
| const arrows = [ | |
| " - ", | |
| "←", | |
| "→","⇒", | |
| ":", ":", | |
| "<","<<","<<","≪","«", | |
| ">",">>",">>","≫","»", | |
| "[<<≪«][-ー==]", // 二文字組み合わせやじるし | |
| "[-ー==][>>≫»]"]; | |
| const _A_ = s + "(?:" + arrows.join("|") + ")" + s; | |
| const next_id = next + _A_ + id ; | |
| const id_next = id + _A_ + next; | |
| //const prev_id = s + prev + _A_ + id + s; | |
| //const id_prev = s + id + _A_ + prev + s; | |
| const 主米 = $('.description').text(); | |
| var m = _.reduce([next_id, id_next], (c,re) => { | |
| return c || 主米.match(new RegExp(re, 'i')); | |
| },false); | |
| OPT.debug && alert(!!m && !!m[0] ? | |
| '次ID切り出し' + m[0]: | |
| '次パート無し'); | |
| return m && m[1] || ''; | |
| } | |
| /** | |
| * ページの遷移処理。実際にはコンテンツを入れ替えるだけで | |
| * フロントのページは遷移させない | |
| */ | |
| function buffShift() { | |
| $('.progressBar.buf .bar').css('width', '0%'); | |
| var $nextPage = $('#buf-video').contents().find('body'); | |
| // ビデオソース書き換え | |
| var $buf = $nextPage.find('#kusa5 video'); | |
| if (!OPT.buffer || $buf.size() == 0) { | |
| FullScreen.cancel(); | |
| return; | |
| } | |
| // 上部のコメントとかタイトル書き換え | |
| $('.videoHeaderTitle').text($nextPage.find('.videoHeaderTitle').text()); | |
| $('#topVideoInfo').remove(); | |
| $('#videoDetailInformation').append($nextPage.find('#topVideoInfo')); | |
| const nextid = $buf[0].dataset.smid; | |
| const nobuffer = nextid <= $video.data('smid'); | |
| $video.attr('src', $buf.attr('src')); | |
| $video.get(0).dataset.smid = nextid; | |
| loadApiInfo(nextid).then(loadMsg); // メッセージ取得 && 整形登録 | |
| history.pushState(null,null, WATCH + nextid); // url書き換え | |
| if (nobuffer) { | |
| $('#buf-video').remove(); | |
| FullScreen.cancel(); | |
| } else { | |
| setTimeout(()=>createBuf(getNextId()), 10000); | |
| } | |
| } | |
| function createBuf(id) { | |
| $('#buf-video').remove(); | |
| if (!id) | |
| return; | |
| $('#kusa5').append(`<iframe id="buf-video" src="${WATCH + id}" | |
| width="10px" height="10px" />`); | |
| // 次ページの動画読み込み進捗を取得 | |
| setTimeout(() => { | |
| const v = $('#buf-video').contents().find('#kusa5 video')[0]; | |
| const p = $('.progressBar.buf .bar'); | |
| $(v).off('timeupdate').on('timeupdate', _.throttle(ev => { | |
| var w = 100 * v.currentTime / v.duration; | |
| p.css('width', w+'%'); | |
| }, 10000)); | |
| }, 20000); | |
| } | |
| function ngfilter(ch) { | |
| if (ch.t < 100) // 1秒以内。いわゆる0秒コメ | |
| return false; | |
| // NGワード | |
| return _.reduce([ | |
| /[韓荒\[\]]/, | |
| /(くない|くせえ|アンチ|びみょ|チョン)/, | |
| /(イライラ|いらいら)/, | |
| /(キモ|きも|パク|ぱく|エミュ|ウザ|うざ)/, | |
| /(うぜ|ウゼ)[えぇエェ]/, | |
| /(推奨|注意|NG|NG|自演)/, | |
| /(朝鮮|創価|在日)/, | |
| /(イラ|いら)[イいつ]?/, | |
| /(嫌|いや|イヤ)なら/, | |
| /(ゆとり|信者|名人様|視聴者様|赤字|水色|餓鬼)/, | |
| /(萎え|挙手)/, | |
| /(つま|ツマ)[ラら]?[なねんナネン]/, | |
| /(eco|eco|エコノミ|画質|時報|3DS|倍速)/, | |
| /^[ノノ]$/, | |
| /^[\//@@※←↑↓]/, | |
| ], (cary, re) => cary && !ch.c.match(re), true); | |
| } | |
| function xml2chats(xml) { | |
| console.log("xmlは %s ", xml); | |
| return _.chain($(xml).find('chat')) | |
| .map(ch => | |
| ({ t: $(ch).attr('vpos') -0, //cast | |
| c: $(ch).text()})) | |
| // .filter(ngfilter) | |
| .sortBy(c => c.t); | |
| } | |
| function loadMsg(info) { | |
| var getThreadKey; | |
| debugger; | |
| if(info.needs_key==1){ | |
| getThreadKey=$.ajax({ | |
| type:'GET', | |
| url:`http://flapi.nicovideo.jp/api/getthreadkey?thread=${info.thread_id}&language_id=0`, | |
| contentType: "text/plain", | |
| dataType: 'text', | |
| crossDomain: true, | |
| cache: false, | |
| xhrFields: {'withCredentials': true} | |
| }).then(result =>{ | |
| info.threadkey=result.match(/threadkey=(.+?)&/)[1]; | |
| info.requestXml=`<packet><thread thread="${info.thread_id}" version="20090904" user_id="${info.user_id}" threadkey="${info.threadkey}" force_184="1" scores="1" nicoru="1" with_global="1"/><thread_leaves thread="${info.thread_id}" user_id="${info.user_id}" threadkey="${info.threadkey}" force_184="1" scores="1" nicoru="1">0-${Math.ceil(info.l/60)}:100,1000</thread_leaves></packet>`; | |
| return info; | |
| },data => console.log('メッセージロード失敗', data)); | |
| }else{ | |
| getThreadKey=new Promise(function(resolve, reject) { | |
| info.requestXml=`<packet><thread thread="${info.thread_id}" version="20090904" user_id="${info.user_id}" scores="1" nicoru="1" with_global="1"/> | |
| <thread_leaves thread="${info.thread_id}" user_id="${info.user_id}" scores="1" nicoru="1">0-${Math.ceil(info.l/60)}:1000,1000</thread_leaves> | |
| <thread thread="${info.thread_id}" version="20061206" res_from="-5000" fork="1" click_revision="-1" scores="1"/></packet>`; | |
| resolve(info); | |
| }); | |
| } | |
| return getThreadKey.then(info=>{return $.ajax({ | |
| type: 'POST', | |
| url: info.ms, | |
| // サーバーによってCORSで弾かれたりバッドリクエスト判定されたり | |
| // するので application/xmlでもなくtext/xmlでもなく | |
| // この値に落ち着いた | |
| contentType: "text/plain", | |
| dataType: 'xml', | |
| data: info.requestXml, | |
| crossDomain: true, | |
| cache: false, | |
| });}).then( | |
| xml2chats, | |
| data =>{console.log('メッセージロード失敗', data);} | |
| ).then(chats => { | |
| // 時間イベントの発火で、対象メッセージがあれば流す | |
| var lastT = 0; | |
| // 次の動画への繊維などで複数回登録させるのでoff() | |
| $video.off('timeupdate').on('timeupdate', _.throttle(ev => { | |
| // chat.vpos is 1/100 sec. | |
| var v = ev.target; | |
| var t = Math.round(v.currentTime * 100); | |
| chats.filter(ch => lastT < ch.t && ch.t < t) | |
| .forEach(_.throttle(marqueeMsg, 50)); | |
| lastT = t;//更新 | |
| // ついでに動画の進捗バーを更新 | |
| var w = 100 * v.currentTime / v.duration; //in % | |
| $('.progressBar.seek .mainbar').css('width', w+'%'); | |
| $('.controle-panel .current') | |
| .text(UTIL.sec2HHMMSS(v.currentTime)); | |
| $('.controle-panel .duration') | |
| .text(UTIL.sec2HHMMSS(v.duration)); | |
| }, 1000)); | |
| $video.off('progress').on('progress', _.throttle(ev => { | |
| var v = ev.target; | |
| if (v.buffered.length == 0) | |
| return; | |
| var bufTime = v.buffered.end(v.buffered.length-1); | |
| var bw = 100 * bufTime / v.duration; | |
| $('.progressBar.seek .bufferbar').css('width', bw+'%'); | |
| }, 1000)); | |
| }); | |
| } | |
| /** 動画URLなどの情報を取得してPromiseを返す。 | |
| * キャリーされる値はクエリストリングをオブジェクトにした奴 | |
| */ | |
| function loadApiInfo(id) { | |
| return $.ajax({ | |
| 'type': 'GET', | |
| 'url': ASKURL + id, | |
| 'crossDomain': true, | |
| 'cache': false, | |
| 'xhrFields': {'withCredentials': true} // Cookie認証が必要 | |
| }).then(qs => _.reduce(qs.split('&'), (o, k_v)=>{ | |
| var a = _.map(k_v.split('='), decodeURIComponent); | |
| o[a[0]] = a[1]; | |
| return o; // クエリストリングをオブジェクトにした奴 | |
| },{})); | |
| } | |
| function marqueeMsg(ch) { | |
| const baseW = $('#kusa5').width() + 10; | |
| const hasMsg = $('#kusa5 .msg').size() > 0; | |
| const $m = $('<span class="msg"/>').text(ch.c); | |
| $m.css('transform', `translate3d(${baseW}px, 0, 0)`); | |
| $video.after($m); | |
| function hasRightSpace(l) { | |
| // 一番右端にあるmsgの右端の位置 | |
| var bigwidth = _.max(_.map($('#kusa5').find(l), | |
| // offsetLeftだと0が返る | |
| l => $(l).position().left + l.scrollWidth)); | |
| var rigthSpace = baseW - bigwidth; | |
| // 比率係数は適当。文字が重なるようなら要調整 | |
| // transition速度(つまりアニメーション再生時間)と関係 | |
| return rigthSpace > $m.width() * 0.45; | |
| } | |
| const line = !hasMsg || hasRightSpace('.l1') ? 'l1' : | |
| hasRightSpace('.l2') ? 'l2' : | |
| hasRightSpace('.l3') ? 'l3' : | |
| hasRightSpace('.l4') ? 'l4' : | |
| hasRightSpace('.l5') ? 'l5' : | |
| hasRightSpace('.l6') ? 'l6' : | |
| hasRightSpace('.l7') ? 'l7' : | |
| hasRightSpace('.l8') ? 'l8' : | |
| hasRightSpace('.l9') ? 'l9' : | |
| hasRightSpace('.l10') ? 'l10' : | |
| hasRightSpace('.l11') ? 'l11' : | |
| hasRightSpace('.l12') ? 'l12' : | |
| 'l13'; | |
| $m.addClass(line); | |
| //オーバーシュート | |
| $m.css('transform', `translate3d(-${$m.width() + 10}px, 0, 0)`); | |
| //アニメ停止で自動削除 | |
| $m.on('transitionend', ev => $(ev.target).remove()); | |
| } | |
| var UTIL = {}; | |
| UTIL.sec2HHMMSS = function (sec) { | |
| var sec_num = parseInt(sec, 10); // don't forget the second param | |
| var hours = Math.floor(sec_num / 3600); | |
| var minutes = Math.floor((sec_num - (hours * 3600)) / 60); | |
| var seconds = sec_num - (hours * 3600) - (minutes * 60); | |
| if (hours < 10) {hours = "0"+hours;} | |
| if (minutes < 10) {minutes = "0"+minutes;} | |
| if (seconds < 10) {seconds = "0"+seconds;} | |
| return (hours > 0? hours+':' :'') + minutes+':'+seconds; | |
| }; | |
| const FullScreen = {}; | |
| FullScreen.isOpen = () => | |
| document.mozFullScreen || document.webkitIsFullScreen || | |
| (document.fullScreenElement && document.fullScreenElement !== null); | |
| FullScreen.req = (e) => | |
| !!e.mozRequestFullScreen && e.mozRequestFullScreen() || | |
| !!e.requestFullScreen && e.requestFullScreen() || | |
| !!e.webkitRequestFullScreen && e.webkitRequestFullScreen(); | |
| FullScreen.cancel = () => | |
| !!document.mozCancelFullScreen && document.mozCancelFullScreen() || | |
| !!document.cancelFullScreen && document.cancelFullScreen() || | |
| !!document.webkitCancelFullScreen && document.webkitCancelFullScreen(); | |
| FullScreen.toggle = () => | |
| FullScreen.isOpen() ? | |
| FullScreen.cancel() : | |
| FullScreen.req($('#kusa5')[0]); | |
| function rateForm() { | |
| //var rd = [1, 1.2, 1.5, 2, 2.2, 2.5, 3] | |
| var rd = [0.5,1, 1.3463246851125779, 1.6678900230322302, | |
| 1.9680012082762555, 2.249342814692259, 2.514125064795459, | |
| 2.764189394992108, 3.001086195676507,3.5,4.0 ] | |
| .map(v=> | |
| `<input name="nicorate" type="radio" id="rd${v}" | |
| class="btn" value="${v}"> | |
| <label for="rd${v}">${v.toFixed(1)}<span>x</span></label>`); | |
| return `<div class="ratepanel">${rd.join('')}</div>`; | |
| } | |
| const COMMENT = ` | |
| <div class="comment"> | |
| <input type="text" class="l" /><button class="btn l">投稿</button> | |
| </div>`; | |
| const CONTROLE_PANEL = ` | |
| <div class="controle-panel"> | |
| <div class="progressBar seek"> | |
| <span class="bufferbar"/> | |
| <span class="mainbar"/> | |
| </div> | |
| <div class="progressBar buf"><span class="bar"/></div> | |
| <button class="btn toggle ico play"></button> | |
| ${rateForm()} | |
| <button class="btn full ico r"></button> | |
| <button class="btn volume volumeup ico r"><span class="volume-num"></span></button> | |
| <button class="btn volume volumedown ico r"></button> | |
| <button class="btn comment-hidden ico r"></button> | |
| <div class="playtime r"> | |
| <span class="current"></span> | |
| / | |
| <span class="duration"></span> | |
| </div> | |
| </div>`; | |
| function ctrPanel() { | |
| var $panel = $(CONTROLE_PANEL); | |
| $panel.find('.btn.full').click(FullScreen.toggle); | |
| $panel.find('.btn.toggle').click($video.videoToggle); | |
| return $panel; | |
| } | |
| //update Progress Bar control | |
| var updatebar = function(e) { | |
| var bar = $('.progressBar.seek'); | |
| var offset = e.pageX - bar.offset().left; //Click pos | |
| var ratio = Math.min(1, Math.max(0, offset / bar.width())); | |
| //Update bar and video currenttime | |
| $('.progressBar.seek .mainbar').css('width', (ratio * 100)+'%'); | |
| $video[0].currentTime = $video[0].duration * ratio; | |
| return true; | |
| } | |
| /** main というかエントリーポイント */ | |
| ;(function () { | |
| const kusa5 = $('#kusa5') | |
| .append($video) | |
| .append(ctrPanel()); | |
| $('input[name=nicorate]').change(ev => { | |
| localStorage.nicoRate = | |
| $video.get(0).playbackRate = parseFloat($(ev.target).val()); | |
| }); | |
| $('input[value="'+ localStorage.nicoRate +'"]').click(); | |
| $('#kusa5 button.volumeup').click(ev => { | |
| localStorage.nicoVolume = localStorage.nicoVolume++ % 5 + 1; | |
| $('#kusa5 span.volume-num').text(localStorage.nicoVolume); | |
| $video[0].volume = localStorage.nicoVolume * 0.2; | |
| }); | |
| $('#kusa5 button.volumedown').click(ev => { | |
| localStorage.nicoVolume = localStorage.nicoVolume++ % 5 - 1; | |
| $('#kusa5 span.volume-num').text(localStorage.nicoVolume); | |
| $video[0].volume = localStorage.nicoVolume * 0.2; | |
| }); | |
| // デフォルトボリュームの表示 | |
| localStorage.nicoVolume = localStorage.nicoVolume || 5; | |
| $('#kusa5 span.volume-num').text(localStorage.nicoVolume); | |
| $('#kusa5 button.comment-hidden') | |
| .click(ev => kusa5.toggleClass('comment-hidden')); | |
| var promise = loadApiInfo(launchID).then(info => { | |
| $video.attr('src', info.url); | |
| $video.get(0).dataset.smid = launchID; | |
| return info; | |
| }); | |
| if (isIframe) | |
| return; // 以降はフォワードページのみの処理 | |
| /* シークバーのドラッグ処理*/ | |
| var timeDrag = false; /* Drag status */ | |
| $('.progressBar.seek').mousedown(function(e) { | |
| timeDrag = true; | |
| updatebar(e); | |
| }); | |
| $(document).mouseup(function(e) { | |
| if(!timeDrag) | |
| return; | |
| timeDrag = false; | |
| updatebar(e.pageX); | |
| }).mousemove(e=> timeDrag && updatebar(e)); | |
| // ボタン押された時の動作登録 | |
| var keyTbl = []; | |
| keyTbl[32] = $video.videoToggle; //スペースキー | |
| kusa5.keyup(e => { | |
| if (!keyTbl[e.keyCode]) | |
| return; | |
| keyTbl[e.keyCode](); | |
| e.preventDefault(); | |
| }); | |
| kusa5.keydown(e => { | |
| //ボタンの処理が登録されてたらブラウザの動作をうちけす | |
| if (keyTbl[e.keyCode]) | |
| e.preventDefault(); | |
| }); | |
| //メッセージ取得、文字流しとかのループイベント登録 | |
| promise.then(loadMsg); | |
| if (OPT.buffer) // バッファ用のiFrameを作成する | |
| setTimeout(() => createBuf(getNextId()), 10000); | |
| })(); |