# nlフィルタ定義(文字コード判定用なのでこの行は削除しないこと)
# 22/04/17

#----------------------------------------------------------------------------------------
# ポップアップ用スクリプト埋め込み
[Replace]
Name = ポップアップ用スクリプト埋め込み
#URL = (?:www|ch|com)\.nicovideo\.jp/(?:$|category_recent.php|\?g|tag/|search/|thumb/|newarrival|recent|api/getthumbinfo/|ranking|hotlist|channel/|search_video/|watch/|video/|top/)
FullURL = (https?)://(?!ads|.*api)[^/]+\.nicovideo\.jp/(?!api/|thumb[_/]|embed/)
ContentType = text/html
Match<
(?=</head>)
>
Replace<
<script type="text/javascript" src="$URL1://www.nicovideo.jp/local/overlib_mini.js"></script>
<script type="text/javascript" src="$URL1://www.nicovideo.jp/$TS(local/popThumb.js)"></script><CRLF>
>

#----------------------------------------------------------------------------------------
# 上から順に、
# コミュニティ(co)をリンク、それ以外のsmid系、
# mylist/userへのリンク、視聴履歴内動画タイトル、静画
#
# - 【縮退実装2024-08-08】
# - 元URL = (?!www\.nicovideo\.jp/ranking(?:$|\?))(?:www|ext|ch|com)\.nicovideo\.jp/(?:$|category_recent\.php|\?|tag/|search/|newarrival|recent|ranking|history|hotlist|channel/|search_video/|video/|top/|video_top)
# - 検索結果でサムネとタイトルが表示されないから対象URLから外す. 外しても検索結果でポップアップは動作した.
# - ついでにもう存在しないURLを除外する.
# - https://www.nicovideo.jp/video_top でポップアップが動作する動画リンクと動作しない動画リンクが混在する.
#
[Replace] 
Name = ポップアップリンク置換(検索系)
URL = (?!www\.nicovideo\.jp/ranking(?:$|\?))(?:www|ext|ch|com)\.nicovideo\.jp/(?:$|\?|newarrival|recent|hotlist|channel/)
ContentType = text/(?:html|xml)
Multi = TRUE
EachLine = TRUE
Match<
co\d{1,8}+(?!["\\'?.]|&quot;|low|</[vw]|[^<]*>|(?:(?!<a\s).)*</a>|.*(?:</title>|class="search"|style="width:200px;"></td>|unescapeHTML|">[\r\n])|.+\}\);|.+,cc:\d+.*\})
(?<![a-z])(?:sm|nm|so|ca|ax|yo|nl|ig|na|cw|z[a-e]|om|sk|yk)\d{1,8}+(?!["\\'?.]|&quot;|low|</[vw]|[^<]*>|(?:(?!<a\s).)*</a>|[^>]*(?:</title>|class="search"|style="width:200px;"></td>|unescapeHTML|">[\r\n])|.+\}\);|.+,cc:\d+.*\}|.*'\);)
(?:mylist|user)/\d{1,8}+(?:/\d++|)(?!["\\'?.]|&quot;|.+</(?:form|title)>|.*">[\r\n]|[^<]*>|(?:(?!<a\s).)*</a>|<\\|.+\}\);|.+,cc:\d+.*\})
(?<![a-z])im\d{1,8}+(?!["\\'?.]|&quot;|</[vw]|[^<]*>|(?:(?!<a\s).)*</a>|[^>]*(?:</(?:a|title)>|class="search"|style="width:200px;"></td>|unescapeHTML|">[\r\n])|.+\}\);|.+,cc:\d+.*\}|.*'\);)
>
Replace<
<a target="_top" href="http://com.nicovideo.jp/community/$0" onMouseOver="return popThumb2('$0', 0)" onMouseOut="return nd()">$0</a>
<a class="watch" target="_top" href="/watch/$0" onMouseOver="return popThumb2('$0', 0)" onMouseOut="return nd()">$0</a>
<a class="watch" target="_top" href="/$0" onMouseOver="return popThumb2('$0', 0)" onMouseOut="return nd()">$0</a>
<a class="watch" target="_top" href="http://seiga.nicovideo.jp/seiga/$0" onMouseOver="return popThumb2('$0', 0)" onMouseOut="return nd()">$0</a>
>

#----------------------------------------------------------------------------------------
# APIパラメータに nlFilter を付加した時のみ有効になるフィルタ群

# getthumbinfo のパラメータに ?nlFilter を付加した場合、ポップアップリンクの有無に関わらず
# <description><tag>内の実体参照が必ず二重置換されるようになる (video.array と同じ仕様)
[Replace]
Name = 実体参照の仕様を video.array に合わせる(getthumbinfo)
URL = ext\.nicovideo\.jp/api/getthumbinfo/\w{2}\d+\?nlFilter
Multi = TRUE
EachLine = TRUE
Match<
&amp;((?:amp|lt|gt);)(?![^<>]*</(?!description))
&quot;(?![^<>]*</(?!description))
&apos;(?![^<>]*</(?!description))
&(?![^<>]*</(?!description|tag))
>
Replace<
&$1
"
'
&amp;
>

[Replace]
Name = ポップアップリンク置換(getthumbinfo/video.array)
URL = (?:ext\.nicovideo\.jp/api/getthumbinfo/\w{2}\d+\?|i\.nicovideo\.jp/v3/video\.array\?(?:|v=[\w,]+&))nlFilter
Multi = TRUE
EachLine = TRUE
Match<
(?<!href="|&quot;)https?://[^/]+\.nicovideo\.jp/[a-z/]+\d+(?:\?eco=1)?(?![^<>]*>|[^<>]*</(?!description|tag|last_res_body)|&quot;|"&gt;|&lt;/a)
(?<!href="|&quot;|"&gt;|h)h?(ttps?://(?:(?!&(?:quot|lt|gt);)[-\w:./?!&~#=%;+])+)(?![^<>]*>|[^<>]*</(?!description|tag|last_res_body))
(?:(?<![a-z])(?:sm|nm|so|ca|ax|yo|nl|ig|na|cw|z[a-e]|om|sk|yk)\d{1,8}+|(?:sm|so)\d{7,8}+)(?:\?eco=1)?(?![^<>]*>|[^<>]*</(?!description|tag|last_res_body)|&quot;|"|&lt;/a)
watch/\d{10}+(?![^<>]*>|[^<>]*</(?!description|tag|last_res_body)|&quot;|"|&lt;/a)
(?:mylist|user)/\d{1,8}+(?![^<>]*>|[^<>]*</(?!description|tag|last_res_body)|&quot;|"|&lt;/a)
(?<![a-z])co\d{1,8}+(?![^<>]*>|[^<>]*</(?!description|tag|last_res_body)|&quot;|"|&lt;/a)
(?<![a-z])ch\d{1,8}+(?![^<>]*>|[^<>]*</(?!description|tag|last_res_body)|&quot;|"|&lt;/a)
(?<![a-z])lv\d{1,9}+(?![^<>]*>|[^<>]*</(?!description|tag|last_res_body)|&quot;|"|&lt;/a)
(?<![a-z])(?:sg|mg)\d{1,8}+(?![^<>]*>|[^<>]*</(?!description|tag|last_res_body)|&quot;|"|&lt;/a)
(?<![a-z])im\d{1,8}+(?![^<>]*>|[^<>]*</(?!description|tag|last_res_body)|&quot;|"|&lt;/a)
(?<![a-z])nc\d{1,8}+(?![^<>]*>|[^<>]*</(?!description|tag|last_res_body)|&quot;|"|&lt;/a)
(?<![a-z])ar\d{1,8}+(?![^<>]*>|[^<>]*</(?!description|tag|last_res_body)|&quot;|"|&lt;/a)
(?<![a-z])gm\d{1,8}+(?![^<>]*>|[^<>]*</(?!description|tag|last_res_body)|&quot;|"|&lt;/a)
series/\d{1,8}+(?![^<>]*>|[^<>]*</(?!description|tag|last_res_body)|&quot;|"|&lt;/a)
>
Replace<
&lt;a href="$0"&gt;$0&lt;/a&gt;
&lt;a href="h$1" target="_blank"&gt;$0&lt;/a&gt;
&lt;a href="https://www.nicovideo.jp/watch/$0" onMouseOver="popThumb2('$0', 0)" onMouseOut="nd()" class="watch"&gt;$0&lt;/a&gt;
&lt;a href="https://www.nicovideo.jp/$0" onMouseOver="popThumb2('$0', 0)" onMouseOut="nd()" class="watch"&gt;$0&lt;/a&gt;
&lt;a href="https://www.nicovideo.jp/$0" onMouseOver="popThumb2('$0', 0)" onMouseOut="nd()"&gt;$0&lt;/a&gt;
&lt;a href="https://com.nicovideo.jp/community/$0" onMouseOver="popThumb2('$0', 0)" onMouseOut="nd()"&gt;$0&lt;/a&gt;
&lt;a href="https://ch.nicovideo.jp/channel/$0" onMouseOver="popThumb2('$0', 0)" onMouseOut="nd()"&gt;$0&lt;/a&gt;
&lt;a href="http://live.nicovideo.jp/watch/$0" onMouseOver="popThumb2('$0', 0)" onMouseOut="nd()"&gt;$0&lt;/a&gt;
&lt;a href="http://seiga.nicovideo.jp/watch/$0" onMouseOver="popThumb2('$0', 0)" onMouseOut="nd()" class="watch"&gt;$0&lt;/a&gt;
&lt;a href="http://seiga.nicovideo.jp/seiga/$0" onMouseOver="popThumb2('$0', 0)" onMouseOut="nd()"&gt;$0&lt;/a&gt;
&lt;a href="http://commons.nicovideo.jp/material/$0"&gt;$0&lt;/a&gt;
&lt;a href="https://ch.nicovideo.jp/article/$0"&gt;$0&lt;/a&gt;
&lt;a href="https://game.nicovideo.jp/atsumaru/games/$0"&gt;$0&lt;/a&gt;
&lt;a href="https://www.nicovideo.jp/$0"&gt;$0&lt;/a&gt;
>

[Replace]
Name = ポップアップ追加(getthumbinfo/video.array)
URL = (?:ext\.nicovideo\.jp/api/getthumbinfo/\w{2}\d+\?|i\.nicovideo\.jp/v3/video\.array\?(?:|v=[\w,]+&))nlFilter
Multi = TRUE
EachLine = TRUE
Match<
(?:<|&lt;)a href="https?://[^.]+.nicovideo.jp/(?:user/\d+/)?((?:mylist|user|community|channel|seiga)/\w{2}\d+)(?:\?[^"]*)?"(?=>|&gt;)
(?:<|&lt;)a href="https?://[^.]+.nicovideo.jp/(watch/\w{2}\d+)(?:\?[^"]*)?"(?:| target="_blank")(?=>|&gt;)
>
Replace<
$0 onMouseOver="popThumb2('$1', 0)" onMouseOut="nd()"
$0 onMouseOver="popThumb2('$1', 0)" onMouseOut="nd()" class="watch"
>

[Replace]
Name = キャッシュ済動画のリンク色変更(getthumbinfo/video.array)
URL = (?:ext\.nicovideo\.jp/api/getthumbinfo/\w{2}\d+\?|i\.nicovideo\.jp/v3/video\.array\?v=\w{2}\d+&)nlFilter
Multi = TRUE
idGroup = 2
Match<
((?:<|&lt;)a href="https?://www\.nicovideo\.jp/watch/(\w{2}\d+)")((?:(?!>|&gt;).)+class="watch")
>
Replace<
$1 style="color:#<C00000$$C08000$$008000$$808000>;"$3
>

# 複数動画の場合はパフォーマンスが悪くなるので threadId を対象としない
[Replace]
Name = キャッシュ済動画のリンク色変更(video.array/複数動画)
URL = i\.nicovideo\.jp/v3/video\.array\?(?:|v=[\w,]+&)nlFilter
Multi = TRUE
idGroup = 2
Match<
((?:<|&lt;)a href="https?://www\.nicovideo\.jp/watch/([a-z]{2}\d+)")((?:(?!>|&gt;|style=).)+class="watch")
>
Replace<
$1 style="color:#<C00000$$C08000$$008000$$808000>;"$3
>

#----------------------------------------------------------------------------------------
[Replace]
Name = ポップアップ追加(wwwドメイン汎用)
URL = www\.nicovideo\.jp/
ContentType = text/(?:html|plain|xml)
Multi = TRUE
Match<
(<a\s[^>]*href="\s*(?:|/|[^"]+?(?:video|live)_?id=|
[^"]*?https?://(?:www|live|ch|com|seiga)\.nicovideo\.jp/(?:gate/)?|
https?://rd\.nicovideo\.jp/cc/[^/]+/|/ch[^/]+/video/)
((?:watch/|mylist/|user/|channel/|community/|seiga/)?(?:(?!nw|pk|ap|gm)\w{2}\d++|#id#|%id%))(?:|\?(?!playlist_type)[^"]++)"
(?:(?!popThumb|title=)[^>])*(?: title="[^"]+"(?:(?!vocaloid_top)[^>])*)?)(>\s*+)
(?!<img|<span class="time"|(?:一般|プレミアム)回線で視聴)
>
Replace<
$1 onMouseOver="return popThumb2('$2', 0)" onMouseOut="return nd()"$3
>

#----------------------------------------------------------------------------------------
# kakorokuRecorderが誤パースするのでwatch/lv〜を対象から外す
[Replace]
Name = ポップアップ追加(wwwドメイン以外汎用)
URL = (?!www|ads)[^/]+\.nicovideo\.jp/(?!api/|thumb[_/]|embed/|watch/lv\d+)
ContentType = text/html
Multi = TRUE
Match<
(<a [^>]*href="\s*(?:[^"]+?(?:video|live)_?id=|
[^"]*?https?://(?:www|live|ch|com|seiga)\.nicovideo\.jp/(?:gate/)?|
https?://rd\.nicovideo\.jp/cc/nicotop_[^/]+/|/ch[^/]+/video/)
((?:watch/|mylist/|user/|channel/|community/|seiga/)?(?:\w{2}\d+|#id#|%id%))(?:[\?&][^"]*)?"
(?:(?!popThumb|timeshift_watch|title=)[^>])*(?: title="[^"]+"[^>]*)?)(>\s*)(?!<img)
>
Replace<
$1 onMouseOver="return popThumb2('$2', 0)" onMouseOut="return nd()"$3
>

#----------------------------------------------------------------------------------------
[Replace]
Name = ポップアップ追加(flog)
URL = www\.nicovideo\.jp/(?:$|video_top|category_recent\.php)
Multi = TRUE
EachLine = TRUE
Match<
(<a href="#link#\?top_flog"(?:(?!title=)[^>])*(?: title="[^"]+"[^>]*)?)(>\s*)(?!<img)
\{link:"http://www\.flog\.jp/w\.php/https?://www\.nicovideo\.jp/watch/(\w{2}\d+)"
>
Replace<
$1 onMouseOver="return popThumb2('#id#', 0)" onMouseOut="return nd()"$2
$0,id:"$1"
>

#----------------------------------------------------------------------------------------
[Replace]
Name = ポップアップ追加(静画)
URL = seiga\.nicovideo\.jp/
ContentType = text/html
Multi = TRUE
Match<
<a [^>]*href="(?:https?://seiga\.nicovideo.jp/|/|)(?:bbs|watch|seiga)/((?:sg|im|mg)\d+)[^"]*"
>
Replace<
$0 onMouseOver="return popThumb2('$1', 0)" onMouseOut="return nd()"
>

#----------------------------------------------------------------------------------------
[Replace]
Name = ポップアップ追加(世界の新着動画)
URL = live\.nicovideo\.jp/newworld
Multi = TRUE
Match<
<a [^>]*href="https?://www\.nicovideo\.jp/(watch/\w{2}\d+)[^"]*"
>
Replace<
$0 onMouseOver="return popThumb2('$1', 0)" onMouseOut="return nd()"
>

#----------------------------------------------------------------------------------------
[Script]
Name = ポップアップ追加(検索系埋込みニコニ広告)
URL = www\.nicovideo\.jp/(?:tag|search)/
ContentType = text/html
Append<
NicoCache_nl.moHooksAds.addEarly(function(item) {
  "use strict";
  var counterHref = \$(item).find(".count.ads .value a").attr("href");
  var m = counterHref.match(/publish\/([a-z]{2}\d+)/);
  if (m) {
    var id = m[1];
    \$(item).find(".itemTitle a")
      .mouseenter(function() { return popThumb2(id, 0); })
      .mouseleave(function() { return nd(); });
  }
});
>

#----------------------------------------------------------------------------------------
[Script]
Name = ポップアップ追加(マイページ・ユーザーページ)
URL = www\.nicovideo\.jp/(?:my|user/\d+)(?:/|\?|$)
ContentType = text/html
Append<
NicoCache_nl.moHooks.addLazy(function(item) {
  "use strict";
  var anchors = item.querySelectorAll("a");
  for (var i = 0; i < anchors.length; i++) {
    var anchor = anchors[i];
    if (!anchor.href) continue;
    var m = anchor.href.match(new RegExp("/((?:watch/|mylist/|user/|channel/|community/|seiga/)?(?:(?!nw|pk|ap|gm)\\\\w{2}\\\\d+))"));
    if (!m) continue;
    var id = m[1];
    (function(id) {
      anchor.addEventListener("mouseover", function() { return popThumb2(id, 0) });
      anchor.addEventListener("mouseout", function() { return nd() });
    })(id);
  }
}, {all: true});
>

#----------------------------------------------------------------------------------------
[Script]
Name = ポップアップ追加(静画タグ)
URL = seiga\.nicovideo\.jp/seiga/
ContentType = text/html
Append<
document.addEventListener("DOMContentLoaded", function() {
  "use strict";
  const pattern = /((?:sg|im|mg|sm|nm|so)\d+)/g;
  var tags_ul = document.querySelector(".illust_tag ul");
  new MutationObserver(function() {
    var anchors = tags_ul.querySelectorAll("li.tag > a");
    for (var i = 0; i < anchors.length; i++) {
      var anchor = anchors[i];
      if (anchor.querySelector("span")) continue;
      var m = anchor.innerHTML.match(pattern);
      if (m) {
        anchor.innerHTML = anchor.innerHTML.replace(pattern, '<span>\$1</span>');
        var spans = anchor.querySelectorAll("span");
        for (var i = 0; i < spans.length; i++) {
          var span = spans[i];
          var id = spans[i].innerText;
          (function(span, id) {
            span.addEventListener("mouseover", function() { return popThumb2(id, 0) });
            span.addEventListener("mouseout", function() { return nd() });
          })(span, id);
        }
      }
    }
  }).observe(tags_ul, {childList: true});
});
>

#----------------------------------------------------------------------------------------
[Script]
Name = ポップアップ追加(静画コメント)
URL = seiga\.nicovideo\.jp/seiga/
ContentType = text/html
Append<
document.addEventListener("DOMContentLoaded", function() {
  "use strict";
  var F = function(list) {
    var anchors = list.querySelectorAll("a");
    for (var i = 0; i < anchors.length; i++) {
      var anchor = anchors[i];
      if (anchor._popThumbed) continue;
      if (!anchor.href) continue;
      var m = anchor.href.match(new RegExp("/((?:watch/|mylist/|user/|channel/|community/|seiga/)?(?:(?!nw|pk|ap|gm)\\\\w{2}\\\\d+))"));
      if (!m) continue;
      var id = m[1];
      (function(id) {
        anchor.addEventListener("mouseover", function() { return popThumb2(id, 0) });
        anchor.addEventListener("mouseout", function() { return nd() });
      })(id);
      anchor._popThumbed = true;
    }
  };
  var comment_list = document.querySelector("#ko_comment #comment_list");
  var all_comment_list = document.querySelector("#ko_comment_all #comment_list");
  F(comment_list);
  new MutationObserver(function() {
    F(all_comment_list);
  }).observe(all_comment_list, {childList: true});
});
>

#----------------------------------------------------------------------------------------
[Script]
Name = ポップアップ追加(HTML5動画タグ)
URL = www\.nicovideo\.jp/watch/
ContentType = text/html
Require = "js-initial-watch-data"
Append<
NicoCache_nl.watch.addEventListener('initialized', function() {
  "use strict";
  const pattern = /((?:sg|im|mg|sm|nm|so)\d+)/g;
  var TagList = document.querySelector(".TagList");
  var F = function() {
    var anchors = TagList.querySelectorAll("a.TagItem-name");
    for (var i = 0; i < anchors.length; i++) {
      var anchor = anchors[i];
      if (anchor.querySelector("span")) continue;
      var m = anchor.innerHTML.match(pattern);
      if (m) {
        anchor.innerHTML = anchor.innerHTML.replace(pattern, '<span>\$1</span>');
        var spans = anchor.querySelectorAll("span");
        for (var i = 0; i < spans.length; i++) {
          var span = spans[i];
          var id = spans[i].innerText;
          (function(span, id) {
            span.addEventListener("mouseover", function() { return popThumb2(id, 0) });
            span.addEventListener("mouseout", function() { return nd() });
          })(span, id);
        }
      }
    }
  };
  F();
  new MutationObserver(F).observe(TagList, {childList: true});
});
>

