SmartNicorepo

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

当前为 2015-11-02 提交的版本,查看 最新版本

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