NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @namespace https://tampermonkey.myso.kr/ // @name 네이버 블로그 나만 이웃 자동 정리 // @description 네이버 블로그에 나만 이웃 중인 이웃을 자동으로 정리해줍니다. // @copyright 2021, myso (https://tampermonkey.myso.kr) // @license Apache-2.0 // @version 1.0.14 // @updateURL https://github.com/myso-kr/kr.myso.tampermonkey/raw/master/service/com.naver.blog-crossfollow.user.js // @downloadURL https://github.com/myso-kr/kr.myso.tampermonkey/raw/master/service/com.naver.blog-crossfollow.user.js // @author Won Choi // @connect naver.com // @match https://admin.blog.naver.com/* // @grant GM_addStyle // @require https://cdn.jsdelivr.net/npm/kr.myso.tampermonkey@1.0.24/assets/vendor/gm-app.js // @require https://cdn.jsdelivr.net/npm/kr.myso.tampermonkey@1.0.24/assets/donation.js // ==/UserScript== // ==OpenUserJS== // @author myso // ==/OpenUserJS== GM_App(async function main() { async function search_buddy_me_page(page = 1, results = []) { const blogId = new URL(location.href).searchParams.get('blogId') || location.pathname.match(/^\/([^\/]+)/)[1]; const res = await fetch(`https://admin.blog.naver.com/BuddyMeManage.nhn?relation=all&blogId=${blogId}¤tPage=${page}`).then(r=>r.text()); const doc = document.createElement('div'); doc.innerHTML = res; const pagination = Array.from(doc.querySelector('div.paginate_re').children), pagenation_last = pagination[pagination.length - 1]; const has_next = pagenation_last.tagName == 'A' && !!pagenation_last.className, has_next_valid = pagenation_last.tagName != 'STRONG'; const usernames_rows = Array.from(doc.querySelectorAll('tr a[href*="blog.naver.com"], tr a[href*=".blog.me"]')); const usernames = usernames_rows.map(e=>{ const uri = new URL(e.href); const id = (() => e.closest('tr').querySelector('td:first-child input').value)(); const createdAt = (() => new Date('20'+e.closest('tr').querySelector('td:last-child').innerText))(); const nickname = (() => { if(uri.hostname.includes('.blog.me')) return uri.hostname.replace('.blog.me', ''); if(uri.hostname.includes('blog.naver.com')) return uri.pathname.replace('/', ''); return uri.hostname; })(); return { id, nickname, createdAt }; }); results.push(...usernames); return (has_next || has_next_valid) ? search_buddy_me_page(page+1, results) : results.filter((o,i)=>results.indexOf(o)==i); } async function search_buddy_page(page = 1, results = []) { const blogId = new URL(location.href).searchParams.get('blogId') || location.pathname.match(/^\/([^\/]+)/)[1]; const res = await fetch(`https://admin.blog.naver.com/BuddyListManage.nhn?blogId=${blogId}¤tPage=${page}&searchText=&orderType=adddate`).then(r=>r.text()); const doc = document.createElement('div'); doc.innerHTML = res; const pagination = Array.from(doc.querySelector('div.paginate_re').children), pagenation_last = pagination[pagination.length - 1]; const has_next = pagenation_last.tagName == 'A' && !!pagenation_last.className, has_next_valid = pagenation_last.tagName != 'STRONG'; const usernames_rows = Array.from(doc.querySelectorAll('tr a[href*="blog.naver.com"], tr a[href*=".blog.me"]')); const usernames = usernames_rows.map(e=>{ const uri = new URL(e.href); const id = (() => e.closest('tr').querySelector('td:first-child input').value)(); const createdAt = (() => new Date('20'+e.closest('tr').querySelector('td:last-child').innerText))(); const nickname = (() => { if(uri.hostname.includes('.blog.me')) return uri.hostname.replace('.blog.me', ''); if(uri.hostname.includes('blog.naver.com')) return uri.pathname.replace('/', ''); return uri.hostname; })(); return { id, nickname, createdAt }; }); results.push(...usernames); return (has_next || has_next_valid) ? search_buddy_page(page+1, results) : results.filter((o,i)=>results.indexOf(o)==i); } async function search_buddy_me() { const session_timestamp = eval(sessionStorage.getItem('search_buddy_me_timestamp') || '0'); const session_buddy_me = JSON.parse(sessionStorage.getItem('session_buddy_me') || '[]'); if(Date.now() - session_timestamp > 1000 * 60 * 1) { const followers = await search_buddy_me_page(); sessionStorage.setItem('session_buddy_me', JSON.stringify(followers)); sessionStorage.setItem('search_buddy_me_timestamp', Date.now()) return followers; } else { return session_buddy_me; } } async function search_buddy() { const session_timestamp = eval(sessionStorage.getItem('search_buddy_timestamp') || '0'); const session_buddy = JSON.parse(sessionStorage.getItem('session_buddy') || '[]'); if(Date.now() - session_timestamp > 1000 * 60 * 1) { const following = await search_buddy_page(); sessionStorage.setItem('session_buddy', JSON.stringify(following)); sessionStorage.setItem('search_buddy_timestamp', Date.now()) return following; } else { return session_buddy; } } async function delete_buddy(selfishes) { const uri = new URL('https://admin.blog.naver.com/BuddyDelete.nhn'); const formData = new FormData(); selfishes.map(o=>formData.append('buddyBlogNo', o.id)); formData.append('blogId', location.pathname.replace('/', '')); formData.append('on', ''); formData.append('force', 'true'); await fetch(uri.toString(), { method: 'POST', body: formData }); } //----------------- if(/\.nhn$/.test(location.pathname)) return; const container = document.querySelector('#nav > div:nth-child(4)'); const container_title = container && container.querySelector('.lnb__title'); if(!container_title || container_title.innerText.trim() != '열린이웃') return; GM_donation('.l__container'); GM_addStyle(` .automation-loading:before { content: ''; position: fixed; z-index: 10000000; left: 0; top: 0; right: 0; bottom: 0; margin: auto; background-color: rgba(0, 0, 0, 0.5); } `); const menulist = container.querySelector('ul'); const menuitem = menulist.querySelector('li.selfishes') || document.createElement('li'); if(!menuitem.className) { menuitem.className = 'selfishes'; const menulink = document.createElement('a'); menulink.className = 'lnb__item'; menulink.innerText = '이웃 정리하기' menulink.addEventListener('click', async (e) => { e.preventDefault(); if(!confirm('1주 이상 나를 이웃하지 않은 사람을 모두 정리합니다.\n계속하시겠습니까?')) return; document.documentElement.classList.add('automation-loading'); const following = await search_buddy(); const followers = await search_buddy_me(); const selfishes = following.filter(o=>Date.now() - o.createdAt > 1000 * 60 * 60 * 24 * 7).filter(o=>!followers.find(v=>v.nickname == o.nickname)); const selfishes_count = selfishes.length; if(selfishes.length && confirm(`${selfishes.length}명을 나만 이웃하고 있습니다.\n작업을 계속 하시겠습니까? 이 작업은 취소할 수 없습니다.`)) { const groups = []; for(let i = 0; i < selfishes.length; i += 50) groups.push(selfishes.splice(0, 50)); for(let i = 0; i < groups.length; i++) { const uri = new URL('https://admin.blog.naver.com/BuddyDelete.nhn'); const formData = new FormData(); groups[i].map(o=>formData.append('buddyBlogNo', o.id)); formData.append('blogId', location.pathname.split('/')[1]); formData.append('on', ''); formData.append('groupId', ''); formData.append('force', 'true'); await fetch(uri.toString(), { method: 'POST', body: formData }); } alert(`${selfishes_count}명이 모두 정리 되었습니다.`); } else { alert(`정리할 이웃이 없습니다.`); } document.documentElement.classList.remove('automation-loading'); }); menuitem.append(menulink); menulist.append(menuitem); } });