Greasy Fork镜像 支持简体中文。

Nico Auto Play

Auto play mylist.

  1. // ==UserScript==
  2. // @name Nico Auto Play
  3. // @description:en Auto play mylist.
  4. // @description:ja ニコニコ動画のシリーズ物動画を連続再生するスクリプトです。
  5. // @version 1.0
  6. // @namespace http://twitter.com/foldrr/
  7. // @include http://www.nicovideo.jp/watch/*
  8. // @description Auto play mylist.
  9. // ==/UserScript==
  10. (function(){
  11. /**
  12. * デバッグモード。
  13. */
  14. var DEBUG = 0;
  15. /**
  16. * スクリプト名。
  17. */
  18. var APP_NAME = "nico_auto";
  19. /**
  20. * 常に動画を自動再生するか?
  21. */
  22. var AUTOPLAY_ALWAYS = false;
  23. /**
  24. * 動画の自動再生を制御するフラグ。
  25. * AUTOPLAY_ALWAYSがオフの場合はこのフラグを見て自動再生するか決定する。
  26. */
  27. var AUTOPLAY_FLAG = "a=1";
  28. /**
  29. * 次回分の動画が複数存在する場合でも自動遷移を試みる。
  30. */
  31. var AUTOPLAY_FORCE = true;
  32. /**
  33. * タイマーのインターバル。
  34. */
  35. var INTERVAL = 2 * 1000;
  36. /**
  37. * 動画へのリンクを探すためのXPATH文字列。
  38. */
  39. var XPATH = '//div[@id="WATCHHEADER"]//a';
  40. /**
  41. * 動画へのリンクだけを抜き出すためのプレフィックス。
  42. */
  43. var HREF_TO_WATCH = "http://www.nicovideo.jp/watch/";
  44. /**
  45. * プレイヤーの名前
  46. */
  47. var PLAYER_NAME = "flvplayer";
  48. /**
  49. * プレイヤーの状態(ニコニコ動画の仕様変更により変わる可能性あり)
  50. */
  51. var STATUS_STOPPED = "stopped";
  52. var STATUS_LOAD = "load";
  53. var STATUS_PAUSED = "paused";
  54. var STATUS_PLAYING = "playing";
  55. var STATUS_END = "end";
  56. /**
  57. * ニコニコ動画プレイヤーのオブジェクト
  58. */
  59. // var player = unsafeWindow.$(PLAYER_NAME);
  60. var player = document.getElementById(PLAYER_NAME).wrappedJSObject;
  61. /**
  62. * ニコニコ動画プレイヤーの再生状態
  63. */
  64. var currStatus; // 現在の状態。
  65. var lastStatus; // 直前の状態。
  66. /**
  67. * メイン処理
  68. */
  69. (function(){
  70. // プレイヤーの再生状態を更新する。
  71. refreshStatus();
  72. trace("再生状態: " + lastStatus + " => " + currStatus);
  73. // プレイヤーの再生状態が準備完了になっていれば自動再生を開始する。
  74. if(isReady()){
  75. trace("再生準備完了");
  76. if(isAutoPlay(location.href)){
  77. playMovie();
  78. }
  79. }
  80. // プレイヤーの再生状態が終了した瞬間以外なら処理を始めからやり直す。
  81. if(! hasEnded()){
  82. setTimeout(arguments.callee, INTERVAL);
  83. return;
  84. }
  85. trace("再生終了");
  86. // 動画へのリンクを取得。
  87. var linksToVideo = [];
  88. var links = $X(XPATH, document);
  89. for(var i = 0, n = links.snapshotLength; i < n; i++){
  90. var href = links.snapshotItem(i).href;
  91. if(href.indexOf(HREF_TO_WATCH) == 0){
  92. if(location.href < href){
  93. linksToVideo.push(href);
  94. }
  95. }
  96. }
  97. trace("次回動画候補件数: " + linksToVideo.length + "件");
  98. // 次回分の動画が存在しない場合。
  99. var len = linksToVideo.length;
  100. if(len === 0){
  101. return;
  102. }
  103. // 次回分の動画が1つだけ存在した場合。
  104. if(len == 1){
  105. var linkToNext = linksToVideo[linksToVideo.length - 1];
  106. if(linkToNext){
  107. location.href = linkToNext + "?" + AUTOPLAY_FLAG;
  108. }
  109. return;
  110. }
  111. // 次回分の動画が複数存在する場合。
  112. if(2 <= len){
  113. // 次回分の動画をユーザーが選択するよう促して終了する。
  114. if(! AUTOPLAY_FORCE){
  115. var message = document.createElement("div");
  116. message.innerHTML = "該当する次の動画が複数あるため自動ジャンプを中断します。";
  117. message.style.borderColor = "#FF0000";
  118. message.style.borderStyle = "solid";
  119. message.style.borderWidth = "2px";
  120. message.style.padding = "10px";
  121. message.style.backgroundColor = "#FFDDDD";
  122. message.style.fontSize = "20pt";
  123. message.style.fontWeight = "bold";
  124. player.parentNode.insertBefore(message, player);
  125. return;
  126. }
  127. // 次回動画を自動選択するために情報を取得する。
  128. var infos = [];
  129. for(var i = 0, n = linksToVideo.length; i < n; i++){
  130. var link = linksToVideo[i];
  131. var slash = link.lastIndexOf('/');
  132. var id = link.slice(slash + 1, link.length);
  133. GM_xmlhttpRequest({
  134. method: "GET",
  135. url: "http://ext.nicovideo.jp/api/getthumbinfo/" + id,
  136. onload: function(x){
  137. var parser = new DOMParser();
  138. var dom = parser.parseFromString(x.responseText, "application/xml");
  139. infos.push(dom);
  140. }
  141. });
  142. }
  143. // 次回動画へ自動遷移する。
  144. (function(){
  145. // 全てのタイトルを取得し終わるまで待つ。
  146. if(infos.length < linksToVideo.length){
  147. trace("次回動画の情報を取得中..." +
  148. infos.length + " / " + linksToVideo.length);
  149. setTimeout(arguments.callee, 200);
  150. return;
  151. }
  152. // 全ての次回動画から現在のタイトルに最も似ている動画を探す。
  153. var title = document.title;
  154. var nextIndex = null;
  155. var sameLength = 0;
  156. for(var i = 0, n = infos.length; i < n; i++){
  157. var nextTitle = $XSTR("//title", infos[i]);
  158. var len = equality(title, nextTitle);
  159. if(sameLength < len){
  160. nextIndex = i;
  161. sameLength = len;
  162. }
  163. if(nextIndex !== null){
  164. trace("次回動画候補: " + $XSTR("//title", infos[nextIndex]));
  165. }
  166. }
  167. // 最も似ている動画へ自動遷移する。
  168. if(nextIndex){
  169. var id = $XSTR("//video_id", infos[nextIndex]);
  170. location.href = "http://www.nicovideo.jp/watch/" + id + "?" + AUTOPLAY_FLAG;
  171. }
  172. })();
  173. }
  174. /**
  175. * プレイヤーの再生が終了した瞬間か?
  176. */
  177. function hasEnded(){
  178. return lastStatus === STATUS_PLAYING && currStatus === STATUS_END;
  179. }
  180. /**
  181. * 自動再生するか?
  182. */
  183. function isAutoPlay(href){
  184. return AUTOPLAY_ALWAYS || (0 <= href.indexOf(AUTOPLAY_FLAG));
  185. }
  186. /**
  187. * プレイヤーの準備が完了したか?
  188. */
  189. function isReady(){
  190. return lastStatus === STATUS_STOPPED &&
  191. currStatus === STATUS_PAUSED;
  192. }
  193. // プレイヤーの再生を開始する。
  194. function playMovie(){
  195. try {
  196. if(player.ext_play){
  197. player.ext_play(1);
  198. }
  199. }
  200. catch(e){
  201. }
  202. }
  203. // プレイヤーの再生状態を最新にする。
  204. function refreshStatus(){
  205. // ext_getStatus() でコケる時があるので。
  206. try{
  207. lastStatus = currStatus;
  208. currStatus = player.ext_getStatus();
  209. }
  210. catch(e){
  211. }
  212. }
  213. })();
  214. /**
  215. * ユーティリティ: XPATHから要素を取得する。
  216. */
  217. function $X(xpath, node){
  218. var nodes = node.evaluate(xpath,
  219. node, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  220. return nodes;
  221. }
  222. /**
  223. * ユーティリティ: XPATHから要素の文字列を取得する。
  224. */
  225. function $XSTR(xpath, node){
  226. var r = node.evaluate(xpath,
  227. node, null, XPathResult.STRING_TYPE, null);
  228. return r.stringValue;
  229. }
  230. /**
  231. * ユーティリティ: 文字列が先頭から何文字一致するか調べる。
  232. */
  233. function equality(left, right){
  234. var n = left.length < right.length ? left.length : right.length;
  235. for(var i = 0; i < n; i++){
  236. if(left.charAt(i) !== right.charAt(i)){
  237. break;
  238. }
  239. }
  240. return i;
  241. }
  242. /**
  243. * ユーティリティ: デバッグメッセージを出力する。
  244. */
  245. function trace(s){
  246. if(DEBUG){
  247. console.log(APP_NAME + ": " + s);
  248. }
  249. }
  250. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址