Nico User Ads Hider

ニコニ広告による動画への装飾を削除

2015-12-25 기준 버전입니다. 최신 버전을 확인하세요.

// ==UserScript==
// @name        Nico User Ads Hider
// @namespace   http://userscripts.org/users/121129
// @description ニコニ広告による動画への装飾を削除
// @match       http://www.nicovideo.jp/*
// @match       http://search.nicovideo.jp/*
// @version     5
// @grant       none
// @run-at      document-idle
// ==/UserScript==

;(function() {
  'use strict'
  var handler = function(handleForEachMutation) {
    return function(mutations) {
      for (var m of mutations) handleForEachMutation(m)
    }
  }
  var containsAllClass = function(elem, classTokens) {
    return classTokens.every(function(t) {
      return elem.classList.contains(t)
    })
  }
  var nicovideoObj = function() {
    var isUadLevelClassAdded = function(mutation) {
      return mutation.attributeName === 'class'
          && mutation.target.className.includes('uadlevel')
    }
    var restoreIfUadLevelClassAdded = function(mutation) {
      if (isUadLevelClassAdded(mutation)) {
        mutation.target.className = mutation.oldValue
      }
    }
    var isBalloonShown = function(mutation) {
      var e = mutation.target
      return mutation.attributeName === 'style'
          && e.style.display !== 'none'
          && containsAllClass(e, ['balloon', 'recent', 'active'])
    }
    var hideIfBalloonShown = function(mutation) {
      if (isBalloonShown(mutation)) mutation.target.style.display = 'none'
    }
    var isListRankingPage = function() {
      var p = location.pathname
      return p.startsWith('/ranking/') && p !== '/ranking/'
    }
    var isVideoCommentsShown = function(elem) {
      return elem.hasAttribute('data-video-comments')
          && elem.style.display !== 'none'
    }
    var hideIfVideoCommentsShown = function(mutation) {
      var e = mutation.target
      if (isVideoCommentsShown(e)) e.style.display = 'none'
    }
    var fs = [restoreIfUadLevelClassAdded, hideIfBalloonShown]
    if (isListRankingPage()) fs.push(hideIfVideoCommentsShown)
    return {
      handler: handler(function(mutation) {
        for (var f of fs) f(mutation)
      }),
      options: {
        attributes: true,
        subtree: true,
        attributeOldValue: true,
        attributeFilter: ['class', 'style'],
      },
    }
  }
  var searchObj = function() {
    var isClassMutated = function(mutation) {
      return mutation.type === 'attributes'
          && mutation.attributeName === 'class'
    }
    var removeClassIfContains = function(classToken) {
      return function(elem) {
        var l = elem.classList
        if (l.contains(classToken)) l.remove(classToken)
      }
    }
    var removeGoldAdIfContains = removeClassIfContains('gold-ad')
    var removeSilverAdIfContains = removeClassIfContains('silver-ad')
    var isTooltipShown = function(mutation) {
      return mutation.type === 'childList'
          && mutation.addedNodes.length === 1
          && Boolean(mutation.addedNodes[0].classList)
          && containsAllClass(mutation.addedNodes[0]
                            , ['tooltip', 'fade', 'top', 'in'])
    }
    var hideTooltip = function(mutation) {
      mutation.addedNodes[0].style.display = 'none'
    }
    return {
      handler: handler(function(mutation) {
        if (isClassMutated(mutation)) {
          removeGoldAdIfContains(mutation.target)
          removeSilverAdIfContains(mutation.target)
        } else if (isTooltipShown(mutation)) {
          hideTooltip(mutation)
        }
      }),
      options: {
        attributes: true,
        childList: true,
        subtree: true,
        attributeFilter: ['class'],
      },
    }
  }
  var diffBy = function(location) {
    switch (location.hostname) {
      case 'www.nicovideo.jp': return nicovideoObj()
      case 'search.nicovideo.jp': return searchObj()
      default: throw new Error(location.hostname)
    }
  }
  var observe = function(obj) {
    new MutationObserver(obj.handler).observe(document.body, obj.options)
  }
  observe(diffBy(location))
})()