네이버 블로그 나만 이웃 자동 정리

네이버 블로그에 나만 이웃 중인 이웃을 자동으로 정리해줍니다.

  1. // ==UserScript==
  2. // @namespace https://tampermonkey.myso.kr/
  3. // @name 네이버 블로그 나만 이웃 자동 정리
  4. // @description 네이버 블로그에 나만 이웃 중인 이웃을 자동으로 정리해줍니다.
  5. // @copyright 2021, myso (https://tampermonkey.myso.kr)
  6. // @license Apache-2.0
  7. // @version 1.0.14
  8. // @author Won Choi
  9. // @connect naver.com
  10. // @match https://admin.blog.naver.com/*
  11. // @grant GM_addStyle
  12. // @require https://cdn.jsdelivr.net/npm/kr.myso.tampermonkey@1.0.25/assets/vendor/gm-app.js
  13. // @require https://cdn.jsdelivr.net/npm/kr.myso.tampermonkey@1.0.25/assets/donation.js
  14. // ==/UserScript==
  15.  
  16. // ==OpenUserJS==
  17. // @author myso
  18. // ==/OpenUserJS==
  19. GM_App(async function main() {
  20. async function search_buddy_me_page(page = 1, results = []) {
  21. const blogId = new URL(location.href).searchParams.get('blogId') || location.pathname.match(/^\/([^\/]+)/)[1];
  22. const res = await fetch(`https://admin.blog.naver.com/BuddyMeManage.nhn?relation=all&blogId=${blogId}&currentPage=${page}`).then(r=>r.text());
  23. const doc = document.createElement('div'); doc.innerHTML = res;
  24. const pagination = Array.from(doc.querySelector('div.paginate_re').children), pagenation_last = pagination[pagination.length - 1];
  25. const has_next = pagenation_last.tagName == 'A' && !!pagenation_last.className, has_next_valid = pagenation_last.tagName != 'STRONG';
  26. const usernames_rows = Array.from(doc.querySelectorAll('tr a[href*="blog.naver.com"], tr a[href*=".blog.me"]'));
  27. const usernames = usernames_rows.map(e=>{
  28. const uri = new URL(e.href);
  29. const id = (() => e.closest('tr').querySelector('td:first-child input').value)();
  30. const createdAt = (() => new Date('20'+e.closest('tr').querySelector('td:last-child').innerText))();
  31. const nickname = (() => {
  32. if(uri.hostname.includes('.blog.me')) return uri.hostname.replace('.blog.me', '');
  33. if(uri.hostname.includes('blog.naver.com')) return uri.pathname.replace('/', '');
  34. return uri.hostname;
  35. })();
  36. return { id, nickname, createdAt };
  37. });
  38. results.push(...usernames);
  39. return (has_next || has_next_valid) ? search_buddy_me_page(page+1, results) : results.filter((o,i)=>results.indexOf(o)==i);
  40. }
  41. async function search_buddy_page(page = 1, results = []) {
  42. const blogId = new URL(location.href).searchParams.get('blogId') || location.pathname.match(/^\/([^\/]+)/)[1];
  43. const res = await fetch(`https://admin.blog.naver.com/BuddyListManage.nhn?blogId=${blogId}&currentPage=${page}&searchText=&orderType=adddate`).then(r=>r.text());
  44. const doc = document.createElement('div'); doc.innerHTML = res;
  45. const pagination = Array.from(doc.querySelector('div.paginate_re').children), pagenation_last = pagination[pagination.length - 1];
  46. const has_next = pagenation_last.tagName == 'A' && !!pagenation_last.className, has_next_valid = pagenation_last.tagName != 'STRONG';
  47. const usernames_rows = Array.from(doc.querySelectorAll('tr a[href*="blog.naver.com"], tr a[href*=".blog.me"]'));
  48. const usernames = usernames_rows.map(e=>{
  49. const uri = new URL(e.href);
  50. const id = (() => e.closest('tr').querySelector('td:first-child input').value)();
  51. const createdAt = (() => new Date('20'+e.closest('tr').querySelector('td:last-child').innerText))();
  52. const nickname = (() => {
  53. if(uri.hostname.includes('.blog.me')) return uri.hostname.replace('.blog.me', '');
  54. if(uri.hostname.includes('blog.naver.com')) return uri.pathname.replace('/', '');
  55. return uri.hostname;
  56. })();
  57. return { id, nickname, createdAt };
  58. });
  59. results.push(...usernames);
  60. return (has_next || has_next_valid) ? search_buddy_page(page+1, results) : results.filter((o,i)=>results.indexOf(o)==i);
  61. }
  62. async function search_buddy_me() {
  63. const session_timestamp = eval(sessionStorage.getItem('search_buddy_me_timestamp') || '0');
  64. const session_buddy_me = JSON.parse(sessionStorage.getItem('session_buddy_me') || '[]');
  65. if(Date.now() - session_timestamp > 1000 * 60 * 1) {
  66. const followers = await search_buddy_me_page();
  67. sessionStorage.setItem('session_buddy_me', JSON.stringify(followers));
  68. sessionStorage.setItem('search_buddy_me_timestamp', Date.now())
  69. return followers;
  70. } else {
  71. return session_buddy_me;
  72. }
  73. }
  74. async function search_buddy() {
  75. const session_timestamp = eval(sessionStorage.getItem('search_buddy_timestamp') || '0');
  76. const session_buddy = JSON.parse(sessionStorage.getItem('session_buddy') || '[]');
  77. if(Date.now() - session_timestamp > 1000 * 60 * 1) {
  78. const following = await search_buddy_page();
  79. sessionStorage.setItem('session_buddy', JSON.stringify(following));
  80. sessionStorage.setItem('search_buddy_timestamp', Date.now())
  81. return following;
  82. } else {
  83. return session_buddy;
  84. }
  85. }
  86. async function delete_buddy(selfishes) {
  87. const uri = new URL('https://admin.blog.naver.com/BuddyDelete.nhn');
  88. const formData = new FormData(); selfishes.map(o=>formData.append('buddyBlogNo', o.id));
  89. formData.append('blogId', location.pathname.replace('/', ''));
  90. formData.append('on', ''); formData.append('force', 'true');
  91. await fetch(uri.toString(), { method: 'POST', body: formData });
  92. }
  93. //-----------------
  94. if(/\.nhn$/.test(location.pathname)) return;
  95. const container = document.querySelector('#nav > div:nth-child(4)');
  96. const container_title = container && container.querySelector('.lnb__title');
  97. if(!container_title || container_title.innerText.trim() != '열린이웃') return;
  98. GM_donation('.l__container');
  99. GM_addStyle(`
  100. .automation-loading:before {
  101. content: ''; position: fixed; z-index: 10000000; left: 0; top: 0; right: 0; bottom: 0; margin: auto;
  102. background-color: rgba(0, 0, 0, 0.5);
  103. }
  104. `);
  105. const menulist = container.querySelector('ul');
  106. const menuitem = menulist.querySelector('li.selfishes') || document.createElement('li');
  107. if(!menuitem.className) {
  108. menuitem.className = 'selfishes';
  109. const menulink = document.createElement('a'); menulink.className = 'lnb__item'; menulink.innerText = '이웃 정리하기'
  110. menulink.addEventListener('click', async (e) => {
  111. e.preventDefault(); if(!confirm('1주 이상 나를 이웃하지 않은 사람을 모두 정리합니다.\n계속하시겠습니까?')) return;
  112. document.documentElement.classList.add('automation-loading');
  113. const following = await search_buddy();
  114. const followers = await search_buddy_me();
  115. const selfishes = following.filter(o=>Date.now() - o.createdAt > 1000 * 60 * 60 * 24 * 7).filter(o=>!followers.find(v=>v.nickname == o.nickname));
  116. const selfishes_count = selfishes.length;
  117. if(selfishes.length && confirm(`${selfishes.length}명을 나만 이웃하고 있습니다.\n작업을 계속 하시겠습니까? 작업은 취소할 없습니다.`)) {
  118. const groups = []; for(let i = 0; i < selfishes.length; i += 50) groups.push(selfishes.splice(0, 50));
  119. for(let i = 0; i < groups.length; i++) {
  120. const uri = new URL('https://admin.blog.naver.com/BuddyDelete.nhn');
  121. const formData = new FormData(); groups[i].map(o=>formData.append('buddyBlogNo', o.id));
  122. formData.append('blogId', location.pathname.split('/')[1]);
  123. formData.append('on', ''); formData.append('groupId', ''); formData.append('force', 'true');
  124. await fetch(uri.toString(), { method: 'POST', body: formData });
  125. }
  126. alert(`${selfishes_count}명이 모두 정리 되었습니다.`);
  127. } else {
  128. alert(`정리할 이웃이 없습니다.`);
  129. }
  130. document.documentElement.classList.remove('automation-loading');
  131. });
  132. menuitem.append(menulink);
  133. menulist.append(menuitem);
  134. }
  135. });

QingJ © 2025

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