Warning: fopen(/www/sites/update.greasyfork.icu/index/store/forever/f85fcad59a69a2446bbc2dfb5bc1db87.js): failed to open stream: No space left on device in /www/sites/update.greasyfork.icu/index/scriptControl.php on line 65
// ==UserScript==
// @name NicoLiveCleaner
// @namespace https://greasyfork.org/ja/users/292779-kinako
// @version 1.08
// @description ニコ生各種ページにおいて特定生主を非表示にする。NGワード(正規表現)でも可能。
// @author kinako
// @include http*://live.nicovideo.jp/*
// @include http*://live2.nicovideo.jp/*
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_deleteValue
// @run-at document-body
// @compatible chrome
// @downloadURL none
// ==/UserScript==
(function() {
'use strict';
/*
汚 ( ヾハハヘ
物 ( |W/ヘヘ
は ( |‖//ヘヘ
消 ( ハ‖イ///彡
毒 ( /丶/ ̄\ミ
だ ( /ヘ / ̄‖ミ
| ( レ=  ̄ =、 ‖ミミ
| ( Y三八三>=ヘミミ
!! (〈 L_ソ 〉ノミミ、
⌒⌒ Y 戸弌 i|\ミミ
__i kェェノ / //
/ /`ー―イ //
ヒ_(王)二二二二(王)ノ
L_|_‖ / | ‖ ̄
彡彡\\ | |o‖
彡彡彡L|| |o‖
彡彡//ー仝ー-ヽ/ ̄
|イ二‾\____/ /
|i二 | | |.
丶て_ム___| |.
*/
class Controller
{
constructor(model)
{
this._model = model;
}
main(targets)
{
targets = (Object.prototype.toString.call(targets) === '[object Array]')? targets: [targets];
this._model.setBodyMObserver(targets);
}
receive(flag, data = null)
{
switch(flag) {
case 'record':
this._model.setData('ng_numbers', data);
this._model.iniNGData();
break;
case 'delete':
this._model.deleteData('ng_numbers', data);
break;
case 'ngreg':
this._model.setRegData('ng_keywords', data);
location.reload();
break;
case 'InitializeData':
this._model.iniNGData();
break;
}
}
}
class Model
{
constructor()
{
this.ng_comment_keywords = null;
this.targets = null;
this._ng = {pattern:null, c_pattern:null, numbers:null, keywords:null, c_keywords:null};
this.iniNGData();
}
set ng(val){this._ng.pattern = val};
get ng(){return this._ng.pattern};
set ng_numbers(val){this._ng.numbers = val};
get ng_numbers(){return this._ng.numbers};
set ng_keywords(val){this._ng.keywords = val};
get ng_keywords(){return this._ng.keywords};
//ページロード
setBodyMObserver(targets, options={childList: true})
{
this.targets = targets;
const mo = new MutationObserver(this.setMObserver.bind(this));
mo.observe(document.body, options);
window.addEventListener("DOMContentLoaded", function(e){
mo.disconnect();
});
}
// 動的部分監視
setMObserver(mr, mo)
{
for(let i = 0; i < this.targets.length; i++)
{
if (this.targets[i].Loaded())
{
this.dispatchEvent(this.targets[i]);
if (this.targets[i].mo_options)
{
let mo = new MutationObserver( (mr, _mo)=>{
_mo.disconnect();
this.dispatchEvent(this.targets[i]);
_mo.observe(this.targets[i].element, this.targets[i].mo_options);
});
mo.observe(this.targets[i].element, this.targets[i].mo_options);
}
}
}
}
dispatchEvent(target)
{
let el = (target.element.children)? target.element.children: target.element;
let event = new Event(target.eventType);
for (let x = el.length; x > 0; x--){
el[x-1].addEventListener(target.eventType, target.callback);
el[x-1].dispatchEvent(event);
}
}
// NGデータ設定
iniNGData()
{
// NGコミニュティ番号
let nums, ls = this.getLocalStorage('ng_numbers');
if(ls) {
nums = ls.map(function(str) {
if (/^(co|ch)[0-9]+$/.test(str)) { // コミュニティ&チャンネル
return str + "\\.";
} else if (/^[0-9]+$/.test(str)) { // ユーザー番号
return '/' + str + "\\.";
}
});
this.ng_numbers = ls;
nums = (nums)? nums.join('|'): '';
} else {
nums = '';
this.ng_numbers = [];
}
// NGキーワード
let ls2 = this.getLocalStorage('ng_keywords');
if (ls2) {
ls2 = ls2.filter(function(str) {
return (str !== "" && str !== undefined) ;
});
this.ng_keywords = ls2;
ls2 = (ls2)? ls2.join('|'): '';
} else {
ls2 = '';
this.ng_keywords = [];
}
// 結合
let sep = (nums != '' && ls2 != '')? '|': '';
this.ng = nums + sep + ls2;
}
setData(key, data)
{
let ls = this.getLocalStorage(key);
if (ls) {
if (!ls.includes(data))
{
ls.push(data);
this.setLocalStorage(key, ls);
}
} else {
this.setLocalStorage(key, [data]);
}
}
setRegData(key, data)
{
data = data.trim().split('\n');
data = data.filter(function(str) {
if (str !== "" || str !== undefined) return str;
});
this.setLocalStorage(key, data);
}
deleteData(key, data)
{
let ls = this.getLocalStorage(key);
if (ls)
{
let newArray = ls.filter(n => n !== data);
this.setLocalStorage(key, newArray);
}
}
clearData(key){ GM_deleteValue(key); }
getLocalStorage(key)
{
let ls = GM_getValue(key);
if (ls)
{
//return (!Array.isArray(ls))? JSON.parse(ls): ls;
return this.checkArray(ls);
}
return null;
}
checkArray(data)
{
if (!Array.isArray(data))
{
return this.checkArray(JSON.parse(data));
} else {
return data;
}
}
setLocalStorage(key,data){
GM_setValue(key, JSON.stringify(data));
}
}
class View
{
constructor(controller)
{
this.controller = controller;
this.targets = [];
this.comment_ng = null;
this.video_ng = null;
this.css_prefix = 'nlc';
this._ng = {pattern:null, c_pattern:null, numbers:null, keywords:null, c_keywords:null};
this.setStyle();
}
get ng(){return this._ng.pattern};
get ng_numbers(){return this._ng.numbers};
get ng_keywords(){return this._ng.keywords};
// スタイルシート設定
setStyle()
{
let css = document.createElement('style')
let rule = document.createTextNode(`
/* 削除ボタン */
button.${this.css_prefix}-btn {
font-size: 12px;
color: #fff;
padding: 0 3px;
border-radius: 4px;
opacity: 0.05;
background-color: #404040;
border: none;
}
/* 削除ボタンホバー時 */
button.${this.css_prefix}-btn:hover {
border: none;
opacity: 1;
}
/* ライブページ 削除ボタン */
button[id^="${this.css_prefix}-live-"] {
opacity: 1;
}
/* ライブページ 削除ボタンホバー時 */
button[id^="${this.css_prefix}-live-"]:hover {
border: none;
opacity: 0.8;
}
/* ライブページ 状態コンテナ */
span[id^="${this.css_prefix}-btncontainer"],
span[id^="${this.css_prefix}-state"] {
margin-left: 1em;
}
/* ライブページ NG中状態 */
span[id^="${this.css_prefix}-state"], span[id^="${this.css_prefix}-userstate"] {
letter-spacing: 0.2em;
width: 4em;
text-align: center;
color: #FF0066;
background-color: #FFF;
border: 1px solid #FF0066;
padding: 0em 0.5em;
border-radius: 4px;
}
/* ライブページ ユーザー状態コンテナ */
span[id^="${this.css_prefix}-usercontainer"], span[id^="${this.css_prefix}-userstate"] {
margin-left:0.3em;
}
/* ライブページ ユーザーNG中状態 */
span[id^="${this.css_prefix}-userstate"] {
padding: 0 0.2em;
letter-spacing: 0;
font-size: 11px;
}
/* ライブページザッピング 削除ボタン*/
button[id^="${this.css_prefix}-user"] {
opacity: 0.1;
z-index: 2;
}
/* ライブページザッピング 削除ボタンコンテナ */
div.${this.css_prefix}-zapp-btn-container {
margin: -20px 0 0 0;
width: 100%;
text-align: right;
position: absolute;
z-index: 2;
}
/* ライブページザッピング 削除ボタン*/
button[id^="${this.css_prefix}-zapp"] {
opacity: 0.1;
z-index: 2;
}
/* 検索ページ 削除ボタン */
button[id^="${this.css_prefix}-search"] {
height: 1.5em;
opacity: 0.1;
}
/* トップページ 削除ボタン */
button[id^="${this.css_prefix}-top"] {
opacity: 0.5;
}
/* 番組一覧 削除ボタン */
button[id^="${this.css_prefix}-proglist"] {
padding: 0 3px 0 2px;
}
/* ボタンコンテナ */
div.${this.css_prefix}-proglist-btn-container,
div.${this.css_prefix}-ps4list-btn-container,
div.${this.css_prefix}-rankpic-btn-container,
div.${this.css_prefix}-channel-btn-container,
div.${this.css_prefix}-top-btn-container,
div.${this.css_prefix}-search-btn-container,
div.${this.css_prefix}-search2-btn-container,
div.${this.css_prefix}-search3-btn-container,
span.${this.css_prefix}-modal-img-containner,
div.${this.css_prefix}-left-btn-container {
margin: -1.5em 0 0 0;
width : 100%;
text-align: right;
position: relative;
}
div.${this.css_prefix}-top-btn-container {
margin: -2px 0 0 0px;
position: absolute;
}
div.${this.css_prefix}-search3-btn-container {
margin: 0 0 0 -1em;
position: absolute;
}
span.${this.css_prefix}-modal-img-containner {
margin:0em 0 0 0;
}
div.${this.css_prefix}-right-btn-container {
width: 100%;
text-align: right;
margin-top: 4.5em;
position: absolute;
}
/* オーバーレイ */
div#${this.css_prefix}-overlay {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.7);
opacity: 0;
transition: opacity 0.3s;
z-index: 10000;
}
/* モーダル */
div#${this.css_prefix}-modal-contents {
position: fixed;
top: 50%;
left: 50%;
width: 500px;
height: auto;
text-align: left;
padding: 2em;
transform: translate(-50%, -50%);
background: #fff;
overflow-x: hidden;
/* overflow-y: scroll;*/
border-radius: 10px;
}
#${this.css_prefix}-modal-contents > div:nth-child(2) {
margin-bottom: 1em;
}
div#${this.css_prefix}-modal-contents a {text-decoration: none;}
div#${this.css_prefix}-modal-contents a:link,
div#${this.css_prefix}-modal-contents a:visited{
color:#808080;
}
div#${this.css_prefix}-modal-contents a:hover{
color:#A6A6A6;
}
div#${this.css_prefix}-modal-contents h2 {
margin: 0 0 3px 0;
font-size: 13px;
}
div#${this.css_prefix}-modal-contents img {
width: 40px;
height: 40px;
border-radius: 5px;
}
div#${this.css_prefix}-modal-contents textarea {
width: 100%;
height: 10em;
padding : 0.5em 0 0.5em 0.3em;
}
/* モーダルNGコミュニティ削除ボタン */
button[id^="${this.css_prefix}-ngimg"] {
margin: 0 0 0 -18px;
}
/* モーダルupdateボタン */
button#${this.css_prefix}-regb {
padding: 0 1em;
background-color: #0080FF;
opacity: 1;
margin: 1em 0 0 0;
}
button#${this.css_prefix}-regb:hover { opacity: 0.5;}
/* モーダルcloseボタン */
#${this.css_prefix}-close {
text-align: center;
width: 100%;
margin-top: 2em;
font-size: 15px;
}
/* NGコミュナビゲーション */
#${this.css_prefix}-navi { margin: 0.5em 0 2.5em 0; }
#${this.css_prefix}-navi a,
#${this.css_prefix}-navi-on{
font-size: 12px;
display: inline-block;
width: 2em;
border: 1px solid #0080FF;
color: #0080FF;
text-align: center;
border-radius: 6px;
background-color: #FFF;
margin-right: 0.2em;
}
#${this.css_prefix}-navi-on {
background-color:#0080FF !important;
color: #FFF !important;
}
`);
css.media = 'screen';
css.type = 'text/css';
if (css.styleSheet) {
css.styleSheet.cssText = rule.nodeValue;
} else {
css.appendChild(rule);
};
document.getElementsByTagName('head')[0].appendChild(css);
}
// ページ分岐
main()
{
this.insertMenu();
this.liveTopPage();
this.liveFocusPage();
this.liveListPage();
this.liveSearchPage();
this.liveProgramPage();
this.liveProgramPage2();
this.liveRankingPage();
this.liveTimetablePage();
this.controller.main(this.targets);
}
// 削除
clean(target, ng = this.ng)
{
if (this.checkNG(target, ng)) {
target.remove();
}
}
// HTMLCollection削除(監視無し)
cleanAll(target, ng = this.ng)
{
const t = new Target();
t.element = (toString.call(target) === '[object Function]')? target: ()=> target;
t.eventType = 'cleanAllLoaded';
t.callback = (event)=>{this.clean(event.target, ng);};
this.targets.push(t);
}
// HTMLCollection用ループ削除
loopClean(targets, ng = this.ng)
{
for (let i = targets.length; i > 0; i--) {
this.clean(targets[i-1], ng);
}
}
// 削除だと表示が乱れる場合は非表示
hide(target, ng = this.ng)
{
if (this.checkNG(target, ng)) {
const style = target.getAttribute('style');
const r = new RegExp('display:none');
if (!r.test(style)) {
target.setAttribute('style', 'display:none;' + style);
}
}
}
// HTMLCollection用 非表示
loopHide(targets, ng = this.ng)
{
for (let i = targets.length; i > 0; i--) {
this.hide(targets[i-1], ng);
}
}
checkNG(target, ng)
{
if (ng != null && ng.length > 0 && target) {
const r = new RegExp(ng);
return (r.test(target.outerHTML))? true: false;
}
}
parseCoNumber(t, id = null)
{
if(t != null)
{
let m = /[\/>]{1}((co|ch)[0-9]+)/mg.exec(t.outerHTML);
if (!m) {
m = /\/user\/([0-9]+)/mg.exec(t.outerHTML);
if (m) {
m[2] = 'user';
}
}
if (m && id)
{
const reg = new RegExp('^'+this.css_prefix+'-');
for (let i = 0; i < t.children.length; i++)
{
if (reg.test(t.children[i].getAttribute('class')) || reg.test(t.children[i].id))
{
t.children[i].remove();
}
}
}
return (m)? {number:m[1], prefix:m[2]}: null;
}
return null;
}
convertID(id, number)
{
return this.css_prefix +'-' + id + '-' + number;
}
displayDeleteButtonLivePage(t, id, container_name, state_name)
{
if (t == null) return;
let pcn = this.parseCoNumber(t, id);
if(pcn)
{
let _id = this.convertID(id, pcn.number);
let pb = document.createElement('span');
pb.id = this.convertID(container_name, pcn.number);
let text = document.createElement('span');
text.id = this.convertID(state_name, pcn.number);
text.textContent = 'NG中';
// 追加済み
if (this.ng.length > 0 && this.ng_numbers.includes(pcn.number))
{
pb.appendChild(text)
// 追加する
} else {
let b = this.iniButton(_id, 'x');
b.addEventListener('click', (e)=>{
pb.removeChild(b);
pb.appendChild(text);
this.controller.receive('record', pcn.number);
});
pb.appendChild(b);
}
t.appendChild(pb);
}
}
displayDeleteButtonLiveRoom(t, id)
{
this.displayDeleteButtonLivePage(t, id, 'btncontainer', 'state');
}
displayDeleteButtonLiveUser(t, id)
{
this.displayDeleteButtonLivePage(t, id, 'usercontainer', 'userstate');
}
displayDeleteButtonSingle(t, id)
{
if (t == null) return;
let pcn = this.parseCoNumber(t, id);
if(pcn)
{
let _id = this.convertID(id, pcn.number);
let pb = document.createElement('div');
pb.setAttribute('class', this.css_prefix +'-'+id+ '-btn-container');
let b = this.iniButton(_id, 'x');
pb.appendChild(b);
t.appendChild(pb);
b.addEventListener('click', (e)=>{
e.stopPropagation();
t.remove();
this.controller.receive('record', pcn.number);
});
}
}
displayDeleteButton(targets, id)
{
for (let i = 0; i < targets.length; i++) {
this.displayDeleteButtonSingle( targets[i], id);
}
}
insertMenu()
{
if (!location.href.match(/http(s)*:\/\/live(2*)\.nicovideo\.jp\//)) return;
window.addEventListener("DOMContentLoaded", function(e){
// メニュー部分取得
const menu = document.getElementById('siteHeaderRightMenuContainer');
const li = document.createElement('li');
const a = document.createElement('a');
a.id = 'NicoLiveCleaner';
a.textContent = 'NicoLiveCleaner';
li.appendChild(a);
// ログインアウトリンクの一つ手前に挿入
menu.lastElementChild.parentNode.insertBefore(li, menu.lastElementChild);
a.addEventListener('click', (e)=>{
//メニュー非表示に
menu.style.marginRight = '-100em';
this.displayModal(a.id);
});
}.bind(this));
}
displayModal(id)
{
let overlay, modal, close;
// オーバーレイ
overlay= document.createElement('div');
overlay.setAttribute('id', this.css_prefix + '-overlay');
// モーダルボックス
modal= document.createElement('div');
modal.setAttribute('id', this.css_prefix + '-modal-contents');
// クローズリンク
let cp = document.createElement('div');
cp.id = this.css_prefix + '-close';
close = document.createElement('a');
close.setAttribute('id', 'close');
close.setAttribute('href', '#');
close.innerHTML = 'CLOSE';
// 見出し
let ng_num_title = document.createElement('h2');
ng_num_title.textContent = 'NGコミュニティ&チャンネル&ユーザー';
let ng_reg_title = document.createElement('h2');
ng_reg_title.textContent = 'NGキーワード(正規表現)';
modal.appendChild(ng_num_title);
let ng_container = document.createElement('div');
this.ng_numbers.reverse();
ng_container.appendChild(this.iniNgNumber(this.ng_numbers, 50, 0));
ng_container.appendChild(this.iniNavi(this.ng_numbers, 50, 0));
modal.appendChild(ng_container);
modal.appendChild(ng_reg_title);
modal.appendChild(this.iniNgRegEx(this.ng_keywords));
cp.appendChild(close);
modal.appendChild(cp);
overlay.appendChild(modal);
// コンテンツを表示
document.body.appendChild(overlay);
overlay.style.display = 'block';
overlay.style.opacity = '1';
// モーダル親要素への伝播防止
modal.addEventListener('click', function(e) {
e.stopPropagation();
});
// オーバーレイ削除
overlay.addEventListener('click', function() {
this.style.opacity = '0';
setTimeout(function() {
this.remove();
location.reload();
}.bind(this), 300);
});
// クローズ経由でオーバーレイ削除
close.addEventListener('click', function(e) {
e.preventDefault();
overlay.style.opacity = '0';
setTimeout(function() {
overlay.remove();
location.reload();
}, 300);
});
}
iniNavi(items, block, position)
{
let page = Math.ceil(items.length / block);
let navi = document.createElement('div');
navi.id = this.css_prefix + '-navi'
let navi_on = this.css_prefix + '-navi-on';
if (page > position){
for (let i = 0; i < page; i++) {
let span = document.createElement('span');
let a = document.createElement('a');
if (i == position) {
a.id = navi_on;
}
a.addEventListener('click', function(e) {
console.log(navi);
for (let x = 0; x < navi.children.length; x++)
{
if (navi.children[x].id == navi_on) {
navi.children[x].removeAttribute('id');
} else if (x == i) {
navi.children[x].id = navi_on;
}
}
let parent_id = this.css_prefix + '-ngnumbers';
let base = document.getElementById(parent_id).parentNode;
document.getElementById(parent_id).remove();
this.controller.receive('InitializeData');
this.ng_numbers.reverse();
base.insertBefore(this.iniNgNumber(this.ng_numbers, block, i), base.firstChild);
}.bind(this));
span.textContent = i + 1;
a.appendChild(span);
navi.appendChild(a);
}
}
return navi;
}
iniNgNumber(items, block, position = 0)
{
let outer = document.createElement('div');
outer.id = this.css_prefix + '-ngnumbers';
const start = block * position;
const end = start + block;
const block_items = items.slice(start, end);
if (block_items)
{
for (let i = 0; i < block_items.length; i++)
{
// URL生成
let f = new RegExp('(co|ch)[0-9]+').exec(block_items[i]);
let img_pref, a_url;
let img_url = 'https://secure-dcdn.cdn.nimg.jp/comch/';
if(f != null)
{
if (f[1] == 'co') {
img_pref = 'community';
a_url =['com', img_pref];
} else if (f[1] == 'ch') {
img_pref = 'channel';
a_url = ['ch', img_pref];
}
img_url += img_pref + '-icon/64x64/'+block_items[i]+'.jpg';
} else if (/^[0-9]+/.test(block_items[i])){
img_url = 'https://secure-dcdn.cdn.nimg.jp/nicoaccount/usericon/s/'
img_url += block_items[i].substr(0, block_items[i].length-4)+'/'+block_items[i]+'.jpg';
a_url = ['www', 'user'];
}
let img = document.createElement('img');
img.onerror = function() {
img.src = 'https://secure-dcdn.cdn.nimg.jp/nicoaccount/usericon/defaults/blank_s.jpg'; //代用
}
img.src = img_url;
img.alt = block_items[i];
img.title = img.alt;
let a = document.createElement('a');
a.href = 'https://'+ a_url[0] +'.nicovideo.jp/'+ a_url[1] +'/'+ block_items[i];
a.target = '_blank';
let pb = document.createElement('span');
pb.setAttribute('class', this.css_prefix + '-modal-img-container');
let b = this.iniButton(this.convertID('ngimg', block_items[i]), 'x');
a.appendChild(img);
pb.appendChild(a);
pb.appendChild(b);
outer.appendChild(pb);
b.addEventListener('click', (e)=>{
e.stopPropagation();
pb.remove();
this.controller.receive('delete', block_items[i]);
});
}
}
return outer;
}
iniNgRegEx(items)
{
let outer = document.createElement('div');
let btn = this.iniButton(this.css_prefix+'-regb', 'UPDATE');
let ta = document.createElement('textarea');
if (Array.isArray(items))
{
ta.value = items.join('\n');
}
outer.appendChild(ta);
outer.appendChild(btn);
btn.addEventListener('mousedown', (e)=> {
btn.style.opacity = '0.2';
this.controller.receive('ngreg', ta.value);
});
return outer;
}
iniButton(id, value)
{
let btn = document.createElement('button');
btn.setAttribute('id', id);
btn.setAttribute('class', this.css_prefix + '-btn');
btn.setAttribute('type', 'button');
btn.textContent = value;
return btn;
}
/*
* ニコ生トップページ
*/
liveTopPage()
{
if (!location.href.match(/http(s)*:\/\/live\.nicovideo\.jp(\/\?header|\/)$/)) return;
const programs = new Target();
programs.element = ()=> document.querySelector('div[class^="___contents-area___"]');
programs.eventType = 'focus-program-listMoLoaded';
programs.mo_options = {childList: true, subtree:true};
programs.callback = (event)=>{
this.loopHide(event.target.querySelectorAll('li[class^="___item___"]'));
this.displayDeleteButton(event.target.querySelectorAll(
'div[class^="___program-card___"]'), 'top');
};
this.targets.push(programs);
}
/*
* ニコ生注目番組一覧ページ
*/
liveFocusPage()
{
if (!location.href.match(/http(s)*:\/\/live2\.nicovideo\.jp\/focus$/)) return;
const programs = new Target();
programs.element = ()=> document.querySelector('div[class^="___contents-area___"]');
programs.eventType = 'contentslistMoLoaded';
programs.mo_options = {childList: true, subtree:true};
programs.callback = (event)=>{this.loopHide(event.target.querySelectorAll('li[class^="___item___"]'));};
this.targets.push(programs);
const programs2 = new Target();
programs2.element = ()=> document.querySelector('section[class^="___feature-program-section___"]');
programs2.eventType = 'featurelistMoLoaded';
programs2.mo_options = {childList: true, subtree:true};
programs2.callback = (event)=>{this.loopHide(event.target.querySelectorAll('li[class^="___item___"]'));};
this.targets.push(programs2);
}
/*
* ニコ生番組一覧ページ
*/
liveListPage()
{
if (!location.href.match(/http(s)*:\/\/live\.nicovideo\.jp\/recent\?.*/)) return;
// 番組一覧監視
const programs = new Target();
programs.element = ()=> document.getElementById('onair_stream_list');
programs.eventType = 'user-program-listMoLoaded';
programs.mo_options = {childList: true};
programs.callback = (event)=>{
this.loopClean(event.target.getElementsByClassName('user-program-item'));
this.displayDeleteButton(event.target.getElementsByClassName('user-program-item'), 'proglist');
};
this.targets.push(programs);
// ランキング&ピックアップ監視
const ranking = new Target();
ranking.element = ()=> document.getElementById('contents-block');
ranking.eventType = 'rankinglistMoLoaded';
ranking.mo_options = {childList: true, subtree:true};
ranking.callback = (event)=>{
this.loopClean(event.target.getElementsByTagName('li'));
this.displayDeleteButton(event.target.getElementsByTagName('li'), 'rankpic');
};
this.targets.push(ranking);
// チャンネル部分削除(ページ下部)
const channel = new Target();
channel.element = ()=> document.getElementById('channel-block');
channel.eventType = 'channelMoLoaded';
channel.callback = (event)=>{
this.loopClean(event.target.getElementsByTagName('li'));
this.displayDeleteButton(event.target.getElementsByTagName('li'), 'channel');
};
this.targets.push(channel);
// PS4配信ピックアップ欄
const ps4 = new Target();
ps4.element = ()=> document.getElementById('eden_pickup_program_area');
ps4.eventType = 'ps4-program-listMoLoaded';
ps4.callback = (event)=>{
this.loopClean(event.target.getElementsByClassName('ps4-program-item'));
this.displayDeleteButton(event.target.getElementsByClassName('ps4-program-item'), 'ps4list');
};
this.targets.push(ps4);
}
/*
* ニコ生検索ページ
*/
liveSearchPage()
{
if (!location.href.match(/http(s)*:\/\/live\.nicovideo\.jp\/search\?.*/)) return;
// 検索結果
const t = new Target();
t.element = ()=> document.getElementsByClassName('result-item');
t.eventType = 'cleanAllLoaded';
t.callback = (event)=>{
this.clean(event.target, this.ng);
this.displayDeleteButtonSingle(event.target, 'search');
};
this.targets.push(t);
// 関連チャンネル
const channel = new Target();
channel.element = ()=> document.getElementsByClassName('recommend-channel-list')[0];
channel.eventType = 'recommend-channelMoLoaded';
channel.mo_options = {childList: true, subtree:true, attributes: true};
channel.callback = (event)=>{
this.hide(event.target);
this.displayDeleteButtonSingle(event.target, 'search2');
};
this.targets.push(channel);
// 関連コミュニティ
const community = new Target();
community.element = ()=> document.getElementsByClassName('recommend-community-list')[0];
community.eventType = 'recommend-communityMoLoaded';
community.mo_options = {childList: true, subtree:true, attributes: true};
community.callback = (event)=>{
this.hide(event.target);
this.displayDeleteButtonSingle(event.target, 'search3');
};
this.targets.push(community);
}
/*
* ニコ生旧ライブページ&放送終了後ページ
*/
liveProgramPage()
{
if (!location.href.match(/http(s)*:\/\/live\.nicovideo\.jp\/(watch|gate)\/lv.*/)) return;
// ザッピング番組監視
const zapping = new Target();
zapping.element = ()=> document.getElementById('zapping_area');
zapping.eventType = 'zappingMoLoaded';
zapping.mo_options = {childList: true, subtree:true};
zapping.callback = (event)=>{this.loopHide(event.target.getElementsByClassName('zapping_stream'));};
this.targets.push(zapping);
// こんな番組も見ています
const after = new Target();
after.element = ()=> document.getElementsByClassName('gyokuon_container')[0];
after.eventType = 'gyokuonMoLoaded';
after.mo_options = {childList: true};
after.callback = (event)=>{ this.loopHide(event.target.getElementsByClassName('gyokuon_list_item')); };
this.targets.push(after);
}
/*
* ニコ生html5ライブページ
*/
liveProgramPage2()
{
if (!location.href.match(/http(s)*:\/\/live2\.nicovideo\.jp\/watch\/lv.*/)) return;
// コミュニティ付近にNGボタン表示
const info = new Target();
info.element = ()=> document.querySelector('div[class^="___social-group-information___"] div[class^="___header-area___"]');
info.eventType = 'infoMoLoaded';
info.callback = (event)=>{
this.displayDeleteButtonLiveRoom(event.target.parentNode, 'live');
}
this.targets.push(info);
// ユーザー付近にNGボタン表示
const user = new Target();
user.element = ()=> document.querySelector('div[class^="___user-summary___"]');
user.eventType = 'userLoaded';
user.callback = (event)=>{
this.displayDeleteButtonLiveUser(event.target.querySelector('div[class^="___user-name-area___"]'), 'user');
};
this.targets.push(user);
// ザッピング番組監視
const zapping = new Target();
zapping.element = ()=> document.querySelector('div[class^="___zapping-list-group___"]');
zapping.eventType = 'zappingMoLoaded';
zapping.mo_options = {childList: true, subtree:true};
zapping.callback = (event)=>{
this.loopClean( event.target.querySelectorAll('div[class^="___zapping-item___"]') );
this.displayDeleteButton( event.target.querySelectorAll('div[class^="___zapping-item___"]'), 'zapp');};
this.targets.push(zapping);
}
/*
* ニコ生ランキングページ
*/
liveRankingPage()
{
if (!location.href.match(/http(s)*:\/\/live\.nicovideo\.jp\/ranking.*/)) return;
const ranking = new Target();
ranking.element = ()=> document.getElementById('wrapper');
ranking.eventType = 'rankingMoLoaded';
ranking.mo_options = {childList: true, subtree:true, attributes: true};
ranking.callback = (event)=>{
this.loopClean(event.target.getElementsByClassName('user clearfix ranking_video'));
this.loopClean(event.target.getElementsByTagName('li'));
this.displayDeleteButton( event.target.getElementsByClassName('user clearfix ranking_video'), 'left');
this.displayDeleteButton( event.target.getElementsByTagName('li'), 'right');
};
this.targets.push(ranking);
}
/*
* ニコ生番組表ページ
*/
liveTimetablePage()
{
if (!location.href.match(/http(s)*:\/\/live\.nicovideo\.jp\/timetable.*/)) return;
const list = new Target();
list.element = ()=> document.getElementsByTagName('tbody')[0];
list.eventType = 'TimetableMoLoaded';
list.mo_options = {childList: true, subtree:true};
list.callback = (event)=>{this.clean(event.target);};
this.targets.push(list);
}
}
class Target
{
constructor()
{
this._element = null; // 対象部分
this.eventType = null; // イベント名
this.callback = null; // イベントコールバック
this.mo_options = null; // MutationObserverオプション {childList: true, subtree:true, attributes: true};
}
set element(val) { this._element = val; }
get element() { return (typeof this._element == 'function')? this._element() : this._element; }
Loaded(name = 'loaded', val='')
{
if (Object.prototype.toString.call(this.element) === "[object HTMLCollection]") {
if (this.element.length > 0) {
let last = this.element[this.element.length - 1];
return this.checkload(last);
} else {
return false;
}
} else {
return this.checkload(this.element);
}
}
checkload(element, name = 'loaded', val='')
{
if(element && element.hasAttribute(name) == false) {
element.setAttribute(name, val);
return true;
} else {
return false;
}
}
}
const model = new Model();
const con = new Controller(model);
const view = new View(con);
view._ng = model._ng;
view.main();
})();