SmartNicorepo

ニコレポの「投稿」以外をデフォルトで折りたたむ & お気に入りユーザーに最終更新を表示

目前为 2017-06-01 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name SmartNicorepo
  3. // @namespace https://github.com/segabito/
  4. // @description ニコレポの「投稿」以外をデフォルトで折りたたむ & お気に入りユーザーに最終更新を表示
  5. // @include http://www.nicovideo.jp/my/*
  6. // @include http://www.nicovideo.jp/user/*
  7. // @include http://www.nicovideo.jp/my/fav/user
  8. // @include http://www.nicovideo.jp/mylist/*
  9. // @version 2.4.0
  10. // @grant none
  11. // @noframes
  12. // @require https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.10.1/lodash.js
  13. // ==/UserScript==
  14.  
  15. (function() {
  16. var monkey =
  17. (function() {
  18. var $ = window.jQuery;
  19.  
  20. function addStyle(styles, id) {
  21. var elm = document.createElement('style');
  22. elm.type = 'text/css';
  23. if (id) { elm.id = id; }
  24.  
  25. var text = styles.toString();
  26. text = document.createTextNode(text);
  27. elm.appendChild(text);
  28. var head = document.getElementsByTagName('head');
  29. head = head[0];
  30. head.appendChild(elm);
  31. return elm;
  32. }
  33.  
  34. var __nicorepocss__ = (`
  35. .nicorepo .log.log-user-upload,
  36. .nicorepo .log.log-user-video-upload {
  37. background: #ffe;
  38. }
  39. .nicorepo .log.log-user-upload .log-target-thumbnail,
  40. .nicorepo .log.log-user-video-upload .log-target-thumbnail {
  41. width: auto; height: auto; margin-left: -30px;
  42. }
  43. .nicorepo .log.log-user-upload .video,
  44. .nicorepo .log.log-user-video-upload .video,
  45. .nicorepo .log.log-user-upload .seiga_image
  46. {
  47. height: auto !important;
  48. width: 130px !important;
  49. margin-top: 0px;
  50. margin-bottom: 0 !important;
  51. margin-left: 0 !important;
  52. }
  53. #nicorepo .timeline > .log {
  54. max-height: 500px;
  55. transition: max-height 0.2s ease-in-out 0.2s;
  56. overflow: auto;
  57. }
  58. #nicorepo.show-upload-only .timeline > .log:not(.log-user-upload).log:not(.log-user-video-upload) {
  59. max-height: 22px;
  60. overflow: hidden;
  61. }
  62. #nicorepo .timeline > .log:not(.log-user-upload):not(.log-user-video-upload):hover {
  63. max-height: 500px;
  64. overflow: hidden;
  65. transition: max-height 0.4s ease-in-out;
  66. }
  67. .toggleUpload {
  68. position: absolute;
  69. top: 0px;
  70. right: 16px;
  71. font-weight: bolder;
  72. cursor: pointer;
  73. color: #888;
  74. padding: 6px 8px;
  75. z-index: 1000;
  76. }
  77. .toggleUpload.bottom {
  78. top: auto; right: 32px; bottom: 32px;
  79. }
  80. .show-upload-only .toggleUpload {
  81. color: red;
  82. }
  83. .toggleUpload:after {
  84. content: ': OFF';
  85. }
  86. .show-upload-only .toggleUpload:after {
  87. content: ': ON';
  88. }
  89.  
  90. .togglePagerize {
  91. position: fixed;
  92. bottom: 0;
  93. right: 0;
  94. color: #888;
  95. font-weight: bolder;
  96. cursor: pointer;
  97. border: 2px solid #666;
  98. }
  99. .togglePagerize.enable {
  100. color: red;
  101. }
  102. .togglePagerize:after {
  103. content: ': OFF';
  104. }
  105. .togglePagerize.enable:after {
  106. content: ': ON';
  107. }
  108.  
  109. `).trim();
  110.  
  111. var __favusercss__ = (`
  112.  
  113. #favUser .outer.updating {
  114. }
  115. #favUser .outer.updating * {
  116. cursor: wait;
  117. }
  118. #favUser .outer.done .showNicorepo {
  119. display: none;
  120. }
  121.  
  122. #favUser .nicorepo {
  123. color: #800;
  124. clear: both;
  125. margin-bottom: 24px;
  126. }
  127. #favUser .uploadVideoList, #favUser .seigaUserPage {
  128. font-size: 80%;
  129. margin-left: 16px;
  130. }
  131.  
  132. #favUser .nicorepo.fail {
  133. color: #800;
  134. clear: both;
  135. margin-left: 64px;
  136. }
  137.  
  138.  
  139. #favUser .nicorepo.success {
  140. padding: 8px;
  141. overflow: auto;
  142. border: 1px inset;
  143. max-height: 300px;
  144. }
  145.  
  146. .nicorepo .log-target-thumbnail,
  147. .nicorepo .log-target-info {
  148. display: inline-block;
  149. vertical-align: middle;
  150. }
  151. .nicorepo .log-target-thumbnail .imageContainer {
  152. width: 64px;
  153. height: 48px;
  154. background-color: #fff;
  155. background-size: contain;
  156. background-repeat: no-repeat;
  157. background-position: center;
  158. transition: 0.2s width ease 0.4s, 0.2s height ease 0.4s;
  159. }
  160. .nicorepo .log-target-thumbnail .imageContainer:hover {
  161. width: 128px;
  162. height: 96px;
  163. }
  164. .nicorepo .log-target-info .time {
  165. display: block;
  166. font-size: 80%;
  167. color: black;
  168. }
  169. .nicorepo .log-target-info .logComment {
  170. display: block;
  171. font-size: 80%;
  172. color: black;
  173. }
  174. .nicorepo .log-target-info .logComment:before {
  175. content: '「';
  176. }
  177. .nicorepo .log-target-info .logComment:after {
  178. content: '」';
  179. }
  180. .nicorepo .log-target-info a {
  181. display: inline-block;
  182. min-width: 100px;
  183. }
  184. .nicorepo .log-target-info a:hover {
  185. background: #ccf;
  186. }
  187.  
  188.  
  189. .nicorepo .log.log-user-video-round-number-of-view-counter {
  190. display: none;
  191. }
  192.  
  193. .nicorepo .log-content {
  194. margin: 4px 8px;
  195. position: relative;
  196. }
  197. .nicorepo .log-footer {
  198. position: absolute;
  199. top: 0;
  200. left: 138px;
  201. }
  202. .nicorepo .log-footer a {
  203. font-size: 80%;
  204. color: black;
  205. }
  206.  
  207. .nicorepo .log .time:after {
  208. background: #888;
  209. color: #fff;
  210. border-radius: 4px;
  211. display: inline-block;
  212. padding: 2px 4px;
  213. }
  214. .nicorepo .log.log-user-register-chblog .time:after,
  215. .nicorepo .log.log-user-upload .time:after,
  216. .nicorepo .log.log-user-seiga-image-upload .time:after {
  217. content: '投稿';
  218. background: #866;
  219. }
  220.  
  221. .nicorepo .log.log-user-mylist-add-blomaga .time:after,
  222. .nicorepo .log.log-user-mylist-add .time:after {
  223. content: 'マイリスト';
  224. }
  225. .nicorepo .log.log-user-live-broadcast .time:after {
  226. content: '放送';
  227. }
  228. .nicorepo .log.log-user-seiga-image-clip .time:after {
  229. content: 'クリップ';
  230. }
  231. .nicorepo .log.log-user-video-review .time:after {
  232. content: 'レビュー';
  233. }
  234. .nicorepo .log.log-user-uad-advertise .time:after {
  235. content: '広告';
  236. }
  237.  
  238. .nicorepo .log.log-user-upload {
  239. background: #ffe;
  240. }
  241.  
  242. .nicorepo .log.log-user-upload .log-target-thumbnail,
  243. .nicorepo .log.log-user-seiga-image-upload .log-target-thumbnail {
  244. }
  245. .nicorepo .log.log-user-upload .video,
  246. .nicorepo .log.log-user-seiga-image-upload .seiga_image {
  247. }
  248.  
  249.  
  250. .nicorepo .log-author,
  251. .nicorepo .log-body,
  252. .nicorepo .log-res,
  253. .nicorepo .log-comment,
  254. .nicorepo .log-footer {
  255. display: none !important;
  256. }
  257. `).trim();
  258.  
  259. var __large_thumbnail_css__ = (`
  260.  
  261. .largeThumbnailLink {
  262. display: inline-block;
  263. }
  264.  
  265. .largeThumbnailLink::after {
  266. content: "";
  267. position: fixed;
  268. bottom: -280px;
  269. width: 360px;
  270. height: 270px;
  271. left: 24px;
  272. opacity: 0;
  273. background-color: #fff;
  274. background-size: contain;
  275. background-repeat: no-repeat;
  276. background-position: center center;
  277. transition:
  278. bottom 0.5s ease 0.5s,
  279. z-index 0.5s ease,
  280. box-shadow 0.5s ease 0.5s,
  281. opacity 0.5s ease 0.5s;
  282. z-index: 100000;
  283. pointer-events: none;
  284. }
  285.  
  286. #PAGEBODY .largeThumbnailLink::after {
  287. left: auto;
  288. right: 24px;
  289. }
  290.  
  291. .largeThumbnailLink:hover::after {
  292. position: fixed;
  293. bottom: 32px;
  294. opacity: 1;
  295. box-shadow: 4px 4px 4px #333;
  296. transition:
  297. bottom 0.2s ease,
  298. z-index 0.2s ease,
  299. box-shadow 0.2s ease,
  300. opacity 0.2s ease;
  301. z-index: 100100;
  302. }
  303. `).trim();
  304.  
  305. var __tagrepocss__ = (`
  306. .newVideoChannel .post-item,
  307. .newVideoUser .post-item {
  308. {* background: #ffe;*}
  309. }
  310.  
  311. .newLiveChannel .post-item,
  312. .newLiveUser .post-item {
  313. background: #eee;
  314. }
  315.  
  316. .newVideoUser .contents-thumbnail img.largeThumbnail,
  317. .newVideoOfficial .contents-thumbnail img.largeThumbnail,
  318. .newVideoChannel .contents-thumbnail img.largeThumbnail {
  319. margin-top: -21px;
  320. }
  321.  
  322. `).trim();
  323.  
  324. var failedUrl = {};
  325. var initializeLargeThumbnail = function(type, container, selector) {
  326. console.log('%cinitializeLargeThumbnail: type=%s', 'background: lightgreen;', type);
  327. addStyle(__large_thumbnail_css__);
  328.  
  329. // 大サムネが存在する最初の動画ID。 ソースはちゆ12歳
  330. // ※この数字以降でもごく稀に例外はある。
  331. var threthold = 16371888;
  332. var hasLargeThumbnail = function(videoId) { // return true;
  333. var cid = videoId.substr(0, 2);
  334. if (cid !== 'sm') { return false; }
  335.  
  336. var fid = videoId.substr(2) * 1;
  337. if (fid < threthold) { return false; }
  338.  
  339. return true;
  340. };
  341.  
  342. var onLoadImageError = function() {
  343. console.log('%c large thumbnail load error!', 'background: red;', this);
  344. var src = this.src.replace('.L', '');
  345. var $this = $(this);
  346. $this.off('error').addClass('large-thumbnail-fail');
  347.  
  348. failedUrl[src] = true;
  349. if (this.src !== src) {
  350. this.src = src;
  351. $this
  352. .removeClass('largeThumbnail')
  353. .closest('a')
  354. .removeClass('largeThumbnailLink');
  355. }
  356. };
  357.  
  358. var updatedItems = [];
  359. var each = function(i, v) {
  360. //console.log(i, v); //return;
  361. var href = v.href;
  362. if (typeof href !== 'string' || href.toString().indexOf('/watch/sm') < 0) {
  363. return;
  364. }
  365.  
  366. var videoId = href.replace(/^.+(sm\d+).*$/, '$1');
  367.  
  368. if (!hasLargeThumbnail(videoId)) {
  369. return;
  370. }
  371.  
  372. var $this = $(v);
  373. var $thumbnail = $this.find('img');
  374. var src = $thumbnail.attr('src');
  375. var org = $thumbnail.attr('data-original');
  376. var attr = org ? 'data-original' : 'src';
  377. src = org ? org : src;
  378.  
  379. //console.log('', attr, src, org);
  380.  
  381. if ($this.hasClass('large-thumbnail-fail')) { return; }
  382.  
  383. if (failedUrl[src]) { return; }
  384.  
  385. if (src && src.indexOf('.L') < 0 && src.indexOf('/smile?i=') > 0) {
  386. var url = src.replace('.M', '') + '.L';
  387. if (failedUrl[url]) { return; }
  388. $thumbnail
  389. .on('error', onLoadImageError)
  390. .addClass('largeThumbnail ' + videoId)
  391. .attr(attr, url);
  392.  
  393. $this.addClass('largeThumbnailLink ' + videoId);
  394. updatedItems.push([videoId, url]);
  395. }
  396. };
  397.  
  398. var cssExist = {};
  399. var updateCss = function(items) {
  400. if (items.length < 1) { return; }
  401. var css = [];
  402. for (var i = 0, len = items.length; i < len; i++) {
  403. var videoId = items[i][0], src = items[i][1];
  404. if (cssExist[videoId]) {
  405. continue;
  406. }
  407. cssExist[videoId] = true;
  408. css.push([
  409. '.largeThumbnailLink.', videoId, '::after {',
  410. ' background-image: url(', src, ');',
  411. // ' content: url(', src, ');',
  412. '}',
  413. '\n'].join(''));
  414. }
  415. if (css.length > 0) {
  416. addStyle(css.join(''));
  417. }
  418. };
  419.  
  420. var delayTimer;
  421. var update = function() {
  422. if (delayTimer) {
  423. clearTimeout(delayTimer);
  424. }
  425.  
  426. delayTimer = setTimeout(function() {
  427. //console.log('%cupdate large thumbnail', 'background: lightgreen;');
  428. updatedItems = [];
  429. $(selector).each(each);
  430. updateCss(updatedItems);
  431. delayTimer = null;
  432. }, 500);
  433. };
  434.  
  435. update();
  436.  
  437. $(container).on('DOMNodeInserted', update);
  438. };
  439.  
  440. var initializeSeigaThumbnail = function(type, container, selector) {
  441. console.log('%cinitializeSeigaThumbnail: type=%s', 'background: lightgreen;', type);
  442.  
  443. var onLoadImageError = function() {
  444. console.log('%c large thumbnail load error!', 'background: red;', this);
  445. this.src = this.src.replace(/i$/, 'z');
  446. $(this)
  447. .removeClass('largeThumbnail')
  448. .closest('a')
  449. .removeClass('largeThumbnailLink');
  450. };
  451.  
  452. var updatedItems = [];
  453. var each = function(i, v) {
  454. var href = v.href;
  455. if (typeof href !== 'string' || href.indexOf('/seiga/im') < 0) {
  456. //console.log(i, href, href.indexOf('/seiga/im'), typeof href , v);
  457. return;
  458. }
  459.  
  460. var seigaId = href.replace(/^.+(im\d+).*$/, '$1');
  461.  
  462. var $this = $(v);
  463. var $thumbnail = $this.find('img');
  464. var src = $thumbnail.attr('src');
  465. var org = $thumbnail.attr('data-original');
  466. var attr = org ? 'data-original' : 'src';
  467. src = org ? org : src;
  468.  
  469. if (src && src.match(/thumb\/\d+z$/)) {
  470. var url = src.replace(/z$/, 'i');
  471. $thumbnail
  472. .on('error', onLoadImageError)
  473. .addClass('largeThumbnail ' + seigaId)
  474. .attr(attr, url);
  475.  
  476. $this.addClass('largeThumbnailLink ' + seigaId);
  477. updatedItems.push([seigaId, url]);
  478. }
  479.  
  480. };
  481.  
  482. var cssExist = {};
  483. var updateCss = function(items) {
  484. if (items.length < 1) { return; }
  485. var css = [];
  486. for (var i = 0, len = items.length; i < len; i++) {
  487. var seigaId = items[i][0], src = items[i][1];
  488. if (cssExist[seigaId]) {
  489. continue;
  490. }
  491. cssExist[seigaId] = true;
  492. css.push([
  493. '.largeThumbnailLink.', seigaId, '::after {',
  494. ' background-image: url(', src, ');',
  495. '}',
  496. '\n'].join(''));
  497. }
  498. if (css.length > 0) {
  499. addStyle(css.join(''));
  500. }
  501. };
  502.  
  503. var delayTimer;
  504. var update = function() {
  505. if (delayTimer) {
  506. clearTimeout(delayTimer);
  507. }
  508.  
  509. delayTimer = setTimeout(function() {
  510. //console.log('%cupdate seiga thumbnail', 'background: lightgreen;');
  511. updatedItems = [];
  512. $(selector).each(each);
  513. updateCss(updatedItems);
  514. delayTimer = null;
  515. }, 500);
  516. };
  517.  
  518. update();
  519.  
  520. $(container).on('DOMNodeInserted', update);
  521. };
  522.  
  523.  
  524.  
  525. window.SmartNicorepo = {
  526. model: {},
  527. util: {},
  528. initialize: function() {
  529. this.initializeUserConfig();
  530. if (location.pathname === '/my/fav/user') {
  531. this.initializeFavUser();
  532. } else
  533. if (location.pathname.indexOf('/my/tagrepo/') === 0) {
  534. this.initializeTagrepo();
  535. } else {
  536. this.initializeNicorepo();
  537. this.initializeAutoPageRize();
  538. }
  539. },
  540. initializeUserConfig: function() {
  541. var prefix = 'SmartNicorepo_';
  542. var conf = {
  543. showUploadOnly: false,
  544. autoPagerize: true
  545. };
  546.  
  547. this.config = {
  548. get: function(key) {
  549. try {
  550. if (window.localStorage.hasOwnProperty(prefix + key)) {
  551. return JSON.parse(window.localStorage.getItem(prefix + key));
  552. }
  553. return conf[key];
  554. } catch (e) {
  555. return conf[key];
  556. }
  557. },
  558. set: function(key, value) {
  559. //console.log('%cupdate config {"%s": "%s"}', 'background: cyan', key, value);
  560. window.localStorage.setItem(prefix + key, JSON.stringify(value));
  561. }
  562. };
  563. },
  564. initializeNicorepo: function() {
  565. addStyle(__nicorepocss__, 'nicorepoCss');
  566.  
  567. let config = this.config;
  568. let $nicorepo = $('#nicorepo');
  569. let toggle = () => {
  570. $nicorepo.toggleClass('show-upload-only');
  571. config.set('showUploadOnly', $nicorepo.hasClass('show-upload-only'));
  572. };
  573.  
  574. //$nicorepo.on('dblblick', toggle);
  575. let $button = $('<button class="toggleUpload">投稿だけ表示</button>').click(toggle);
  576.  
  577. let ver = document.querySelector('#MyPageNicorepoApp') ? 'new' : 'old';
  578.  
  579. const updateClass = () => {
  580. const query = ver === 'new' ?
  581. '.NicorepoTimelineItem .log-body strong' :
  582. '.log.log-user-video-upload .log-body, .log.log-user-seiga-image-upload .log-body';
  583. Array.from(document.querySelectorAll(query)).forEach(elm => {
  584. const log = elm.closest(ver === 'new' ? '.NicorepoTimelineItem' : '.log');
  585. if (!log) { return; }
  586. log.classList.add('log-user-upload');
  587. });
  588. };
  589.  
  590. const mutationObserver = new window.MutationObserver((mutations) => {
  591. let isAdded = false;
  592. mutations.forEach(mutation => {
  593. if (mutation.addedNodes && mutation.addedNodes.length > 0) {
  594. isAdded = true;
  595. }
  596. });
  597. if (isAdded) { updateClass(); }
  598. });
  599.  
  600. updateClass();
  601.  
  602. mutationObserver.observe(
  603. //document.querySelector('#MyPageNicorepoApp .nicorepo .timeline'),
  604. //document.querySelector('#nicorepo'),
  605. document.querySelector(ver === 'new ' ? '#MyPageNicorepoApp' : '#nicorepo .timeline'),
  606. {childList: true, characterData: false, attributes: false, subtree: true}
  607. );
  608.  
  609. if (ver === 'new') {
  610. $('.setting-container').before($button);
  611. $('#MyPageNicorepoApp').after($button.clone(true).addClass('bottom'));
  612. } else {
  613. $('.timeline>*:first').before($button);
  614. $('.timeline>*:last').before($button.clone(true).addClass('bottom'));
  615. }
  616. $nicorepo.toggleClass('show-upload-only', config.get('showUploadOnly'));
  617. },
  618. initializeTagrepo: function() {
  619. console.log('%cinitializeTagrepo', 'background: lightgreen;');
  620. addStyle(__tagrepocss__, 'tagrepoCss');
  621. },
  622. initializeFavUser: function() {
  623. addStyle(__favusercss__, 'favUserCss');
  624. // this.loadFavUserList()
  625. // .then($.proxy(function(watchitems) {
  626. // console.log('%c ok:', 'background: #8f8;', watchitems.length);
  627. //
  628. // this._itemList = new window.SmartNicorepo.model.WatchItemList(watchitems);
  629. //
  630. // console.log('item list', this._itemList.getSortedItems());
  631. //
  632. // }, this));
  633. $('.posRight .arrow').each(function(i, elm) {
  634. var $elm = $(elm), $lnk = $elm.clone();
  635. $lnk
  636. .html('<span></span> ニコレポを表示&nbsp;')
  637. .addClass('showNicorepo');
  638. $elm.before($lnk);
  639. });
  640.  
  641. $('.outer .section a').each(function(i, elm) {
  642. var $elm = $(elm), href = $elm.attr('href');
  643. if (href.match(/\/(\d+)$/)) {
  644. var userId = RegExp.$1;
  645. var $video = $('<a class="uploadVideoList">動画一覧</a>')
  646. .attr('href', '/user/' + userId + '/video');
  647. var $seiga = $('<a class="seigaUserPage">静画一覧</a>')
  648. .attr('href', 'http://seiga.nicovideo.jp/user/illust/' + userId);
  649. $elm.after($seiga).after($video);
  650. }
  651. });
  652.  
  653. var getClearBusy = function($elm) {
  654. return function() {
  655. $elm.removeClass('updating').addClass('done');
  656. };
  657. };
  658.  
  659. $('#favUser .showNicorepo').off().on('click', $.proxy(function(e) {
  660. if (e.button !== 0 || e.metaKey || e.shiftKey || e.altKey || e.ctrlKey) {
  661. return;
  662. }
  663. e.preventDefault();
  664. e.stopPropagation();
  665. var $elm = $(e.target);
  666. var userId = $elm.attr('data-nico-nicorepolistid');
  667. if (!userId) { return; }
  668. var $outer = $elm.closest('.outer');
  669. if ($outer.hasClass('updating')) {
  670. return;
  671. }
  672.  
  673. var clearBusy = getClearBusy($outer);
  674. $outer.addClass('updating');
  675. window.setTimeout(clearBusy, 3000);
  676.  
  677. this.loadNicorepo(userId, $outer).then(clearBusy, clearBusy);
  678.  
  679. }, this));
  680. },
  681. initializeAutoPageRize: function() {
  682. let config = this.config;
  683. let $button = $('<button class="togglePagerize">自動読込</button>');
  684. let timer = null;
  685.  
  686. var onButtonClick = () => {
  687. toggle();
  688. updateView();
  689. };
  690. var toggle = () => {
  691. this._isAutoPagerizeEnable = !this._isAutoPagerizeEnable;
  692. config.set('autoPagerize', this._isAutoPagerizeEnable);
  693. if (this._isAutoPagerizeEnable) {
  694. bind();
  695. } else {
  696. unbind();
  697. }
  698. };
  699. let updateView = () => {
  700. $button.toggleClass('enable', this._isAutoPagerizeEnable);
  701. };
  702. let onWindowScroll = _.debounce(this._onWindowScroll.bind(this), 100);
  703. let bind = () => {
  704. $(window).on('scroll', onWindowScroll);
  705. timer = window.setInterval(this._autoPagerize.bind(this), 5000);
  706. };
  707. let unbind = () => {
  708. $(window).off('scroll', onWindowScroll);
  709. window.clearInterval(timer);
  710. };
  711.  
  712.  
  713. $button.click(onButtonClick);
  714. $('body').append($button);
  715.  
  716. this._isAutoPagerizeEnable = config.get('autoPagerize');
  717. if (this._isAutoPagerizeEnable) { bind(); }
  718.  
  719. updateView();
  720. },
  721. _onWindowScroll: function() {
  722. this._autoPagerize();
  723. },
  724. _autoPagerize: function() {
  725. if (!this._isAutoPagerizeEnable) { return; }
  726. //let ver = document.querySelector('#MyPageNicorepoApp') ? 'new' : 'old';
  727.  
  728. // TODO: IntersectionObserverつかえ
  729. let nextPage = //this._nextPage ||
  730. document.querySelector('#MyPageNicorepoApp .next-page, #nicorepo .next-page');
  731. if (!nextPage) { return; }
  732. //this._nextPage = nextPage;
  733.  
  734. let rect = nextPage.getBoundingClientRect();
  735. let isLoading = nextPage.classList.contains('loading');
  736. let isScrollIn = window.innerHeight - rect.top > 0;
  737. //console.info('?', isLoading, isScrollIn, window.innerHeight - rect.top);
  738. if (isScrollIn && !isLoading) {
  739. document.querySelector('#nicorepo .next-page-link').click();
  740. }
  741. },
  742. loadNicorepo: function(userId, $container) {
  743. // http://www.nicovideo.jp/user/[userId]/top?innerPage=1
  744. var url = 'http://www.nicovideo.jp/user/' + userId + '/top?innerPage=1';
  745.  
  746. var fail = function(msg) {
  747. var $fail = $('<div class="nicorepo fail">' + msg + '</div>');
  748. $container.append($fail);
  749. autoScrollIfNeed($fail);
  750. };
  751.  
  752. // ニコレポが画面の一番下よりはみ出していたら見える位置までスクロール
  753. var autoScrollIfNeed = function($target) {
  754. var
  755. scrollTop = $('html').scrollTop(),
  756. targetOffset = $target.offset(),
  757. clientHeight = $(window).innerHeight(),
  758. clientBottom = scrollTop + clientHeight,
  759. targetBottom = targetOffset.top + $target.outerHeight();
  760.  
  761. if (targetBottom > clientBottom) {
  762. $('html').animate({
  763. scrollTop: scrollTop + $target.outerHeight()
  764. }, 500);
  765. }
  766. };
  767.  
  768. var success = function($dom, $logBody) {
  769. var $result = $('<div class="nicorepo success" />');
  770. var $img = $logBody.find('img'), $log = $logBody.find('.log');
  771. $img.each(function() {
  772. var $this = $(this), $parent = $this.parent();
  773. var lazyImg = $this.attr('data-original');
  774. if (lazyImg) {
  775. var $imageContainer = $('<div class="imageContainer"/>');
  776. $imageContainer.css('background-image', 'url(' + lazyImg + ')');
  777. $this.before($imageContainer);
  778. $this.remove();
  779. }
  780. if (window.WatchItLater) {
  781. var href = $parent.attr('href');
  782. if (href) {
  783. $parent.attr('href', href.replace('http://www.nicovideo.jp/watch/', 'http://nico.ms/'));
  784. }
  785. }
  786. });
  787. $logBody.each(function() {
  788. var $this = $(this), time = $this.find('time:first').text(), logComment = $this.find('.log-comment').text();
  789.  
  790. $this.find('.log-target-info>*:first')
  791. .before($('<span class="time">' + time + '</span>'));
  792. if (logComment) {
  793. $this.find('.log-target-info')
  794. .append($('<span class="logComment">' + logComment + '</span>'));
  795. }
  796. });
  797.  
  798. $result.append($logBody);
  799. $container.append($result);
  800. $result.scrollTop(0);
  801.  
  802. autoScrollIfNeed($result);
  803. };
  804.  
  805. return $.ajax({
  806. url: url,
  807. timeout: 30000
  808. }).then(
  809. function(resp) {
  810. var
  811. $dom = $(resp),
  812. // 欲しいのはそのユーザーの「行動」なので、
  813. // xx再生やスタンプみたいなのはいらない
  814. $logBody = $dom.find('.log:not(.log-user-video-round-number-of-view-counter):not(.log-user-action-stamp):not(.log-user-live-video-introduced)');
  815. if ($logBody.length < 1) {
  816. fail('ニコレポが存在しないか、取得に失敗しました');
  817. } else {
  818. success($dom, $logBody);
  819. }
  820. },
  821. function() {
  822. fail('ニコレポの取得に失敗しました');
  823. });
  824.  
  825. },
  826. loadFavUserList: function() {
  827. var def = new $.Deferred();
  828. // このAPIのupdate_timeが期待していた物と違ったのでボツ
  829. // create_timeとupdate_timeはどちらも同じ値が入ってるだけだった。(なんのためにあるんだ?)
  830. //
  831. $.ajax({
  832. url: 'http://www.nicovideo.jp/api/watchitem/list',
  833. timeout: 30000,
  834. complete: function(resp) {
  835. var json;
  836. try {
  837. json = JSON.parse(resp.responseText);
  838. } catch (e) {
  839. console.log('%c parse error: ', 'background: #f88', e);
  840. return def.reject('json parse error');
  841. }
  842.  
  843. if (json.status !== 'ok') {
  844. console.log('%c status error: ', 'background: #f88', json.status);
  845. return def.reject('status error', json.status);
  846. }
  847. return def.resolve(json.watchitem);
  848. },
  849. error: function(req, status, thrown) {
  850. if (status === 'parsererror') {
  851. return;
  852. }
  853. console.log('%c ajax error: ' + status, 'background: #f88', thrown);
  854. return def.reject(status);
  855. }
  856. });
  857. return def.promise();
  858. }
  859.  
  860. };
  861.  
  862.  
  863. window.SmartNicorepo.model.WatchItem = function() { this.initialize.apply(this, arguments); };
  864. window.SmartNicorepo.model.WatchItem.prototype = {
  865. initialize: function(seed) {
  866. this._seed = seed;
  867. this.itemType = seed.item_type || '1';
  868. this.itemId = seed.item_id || '';
  869. if (typeof seed.item_data === 'object') {
  870. var data = seed.item_data;
  871. this.userId = data.id;
  872. this.nickname = data.nickname;
  873. this.thumbnailUrl = data.thumbnail_url;
  874. }
  875. var now = (new Date()).getTime();
  876. this.createTime = new Date(seed.create_time ? seed.create_time * 1000 : now);
  877. this.updateTime = new Date(seed.update_time ? seed.update_time * 1000 : now);
  878. }
  879. };
  880.  
  881. window.SmartNicorepo.model.WatchItemList = function() { this.initialize.apply(this, arguments); };
  882. window.SmartNicorepo.model.WatchItemList.prototype = {
  883. initialize: function(watchItems) {
  884. this._seed = watchItems;
  885. this._items = {};
  886. this._itemArray = [];
  887. for (var i = 0, len = watchItems.length; i < len; i++) {
  888. var item = new window.SmartNicorepo.model.WatchItem(watchItems[i]);
  889. this._items[item.userId] = item;
  890. this._itemArray.push(item);
  891. }
  892. },
  893. getItem: function(userId) {
  894. return this._items[userId];
  895. },
  896. getSortedItems: function() {
  897. var result = this._itemArray.concat();
  898. result.sort(function(a, b) {
  899. return (a.updateTime < b.updateTime) ? 1 : -1;
  900. });
  901. return result;
  902. }
  903. };
  904.  
  905. var removeQuery = function(container) {
  906. const reg = /(^\?nicorepo|ref=)/;
  907. $(container + ' a').each((i, a) => {
  908. const search = a.search || '';
  909. if (reg.test(search)) {
  910. a.search = '';
  911. }
  912. });
  913. };
  914.  
  915.  
  916. window.Nico.onReady(function() {
  917. console.log('%cNico.onReady', 'background: lightgreen;');
  918. if (location.pathname.indexOf('/my/top') === 0) {
  919. initializeLargeThumbnail('nicorepo', '.nicorepo', '.log-target-thumbnail a[href*=nicovideo.jp/watch/sm]:not(.largeThumbnailLink)');
  920. initializeSeigaThumbnail('nicorepo', '.nicorepo', '.log-target-thumbnail a:not(.largeThumbnailLink)');
  921. //initializeSeigaThumbnail('nicorepo', '.nicorepo', '.log-target-thumbnail a[href*=/seiga/im]:not(.largeThumbnailLink)');
  922. $('.nicorepo').on('DOMNodeInserted', _.debounce(() => {
  923. removeQuery('.nicorepo');
  924. }, 1000));
  925. } else
  926. if (location.pathname.indexOf('/my/mylist') === 0) {
  927. initializeLargeThumbnail('mylist', '#mylist', '.thumbContainer a:not(.largeThumbnailLink)');
  928. } else
  929. if (location.pathname.indexOf('/my/video') === 0) {
  930. initializeLargeThumbnail('video', '#video', '.thumbContainer a:not(.largeThumbnailLink)');
  931. } else
  932. if (location.pathname.indexOf('/mylist') === 0) {
  933. initializeLargeThumbnail('openMylist', '#PAGEBODY', '.SYS_box_item a:not(.watch):not(.largeThumbnailLink):visible');
  934. } else
  935. if (location.pathname.match(/\/user\/\d+\/video/)) {
  936. initializeLargeThumbnail('video', '#video', '.thumbContainer a:not(.largeThumbnailLink)');
  937. } else
  938. if (location.pathname.match(/\/user\/\d+\/top/)) {
  939. initializeLargeThumbnail('nicorepo', '.nicorepo', '.log-target-thumbnail a[href*=nicovideo.jp/watch/sm]:not(.largeThumbnailLink)');
  940. } else
  941. if (location.pathname.match(/\/my\/tagrepo\//)) {
  942. initializeLargeThumbnail('tagrepo', '#tagrepo', '.newVideoUser .contents-thumbnail a[href*=nicovideo.jp/watch/sm]:not(.largeThumbnailLink)');
  943. }
  944. });
  945.  
  946. if (location.pathname.indexOf('/mylist') < 0) {
  947. window.SmartNicorepo.initialize();
  948. }
  949.  
  950. }); // end of monkey
  951.  
  952. var gm = document.createElement('script');
  953. gm.id = 'smartNicorepoScript';
  954. gm.setAttribute("type", "text/javascript");
  955. gm.setAttribute("charset", "UTF-8");
  956. gm.appendChild(document.createTextNode("(" + monkey + ")(window)"));
  957. document.body.appendChild(gm);
  958.  
  959. })();

QingJ © 2025

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