SmartNicorepo

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

当前为 2016-07-19 提交的版本,查看 最新版本

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