// ==UserScript==
// @namespace https://tampermonkey.myso.kr/
// @name 네이버 블로그 공감수 순위 어드밴스드
// @description 네이버 블로그의 공감수 순위 기능을 확장합니다.
// @copyright 2021, myso (https://tampermonkey.myso.kr)
// @license Apache-2.0
// @version 1.0.6
// @author Won Choi
// @match https://blog.stat.naver.com/blog/rank/like*
// @grant GM_addStyle
// @grant GM_xmlhttpRequest
// @require https://cdn.jsdelivr.net/npm/kr.myso.tampermonkey@1.0.7/assets/vendor/gm-app.js
// @require https://cdn.jsdelivr.net/npm/kr.myso.tampermonkey@1.0.7/assets/vendor/gm-add-style.js
// @require https://cdn.jsdelivr.net/npm/kr.myso.tampermonkey@1.0.7/assets/vendor/gm-add-script.js
// @require https://cdn.jsdelivr.net/npm/kr.myso.tampermonkey@1.0.7/assets/donation.js
// @downloadURL none
// ==/UserScript==
// ==OpenUserJS==
// @author myso
// ==/OpenUserJS==
async function inject_js(opt) {
return new Promise((resolve, reject) => {
var el = document.createElement('script'); el.type = 'text/javascript';
function resolved() {
el.parentNode.removeChild(el); resolve();
}
if(typeof opt === 'string') {
el.onload = resolved; el.src = opt;
}
if(typeof opt === 'object') {
el.onload = resolved; el.src = opt.src; el.integrity = opt.integrity;
el.setAttribute('crossorigin', 'anonymous');
}
if(typeof opt === 'function') el.textContent = `(${opt})();`;
if(el.src || el.textContent) {
el.onerror = reject;
document.head.prepend(el);
}else reject();
if(typeof opt === 'function') resolved();
});
}
GM_App(async function main() {
GM_donation('.u_ni_stats_detail_wrap');
document.addEventListener('GM_xmlhttpRequest', async (e) => {
const detail = await new Promise((resolve, reject) => GM_xmlhttpRequest({ ...e.detail, onerror: reject, onload: resolve, })).catch(e=>null);
document.dispatchEvent(new CustomEvent(`GM_xmlhttpRequest.${e.detail.uuid}`, { detail }));
})
await inject_js(() => {
function GM_xmlhttpRequest(detail = {}) {
const uuid = detail.uuid = Math.floor(Math.random() * 999999999);
return new Promise((resolve, reject) => {
function callback(e){
document.removeEventListener(`GM_xmlhttpRequest.${uuid}`, callback, false);
return e.detail ? resolve(e.detail) : reject();
}
document.addEventListener(`GM_xmlhttpRequest.${uuid}`, callback, false);
document.dispatchEvent(new CustomEvent(`GM_xmlhttpRequest`, { detail }));
})
}
window.GM_xmlhttpRequest = window.GM_xmlhttpRequest || GM_xmlhttpRequest;
})
await inject_js({ integrity: 'sha512-TFp7JOp8so/oHJrngLI0kn9diZrc0YDr1NrGj1YbzbvSBdGfligjYVRp1xtqlmNCPWpx4xJDhiWSGgUYvqCbBg==', src: 'https://cdnjs.cloudflare.com/ajax/libs/bluebird/3.7.2/bluebird.js' });
await inject_js({ integrity: 'sha512-90vH1Z83AJY9DmlWa8WkjkV79yfS2n2Oxhsi2dZbIv0nC4E6m5AbH8Nh156kkM7JePmqD6tcZsfad1ueoaovww==', src: 'https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.js' });
await inject_js({ integrity: 'sha512-LGXaggshOkD/at6PFNcp2V2unf9LzFq6LE+sChH7ceMTDP0g2kn6Vxwgg7wkPP7AAtX+lmPqPdxB47A0Nz0cMQ==', src: 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment-with-locales.js' });
await inject_js(() => {
async function rank_like(startDate, endDate) {
const rangeDateStart = moment(startDate).toDate();
const rangeDateLimit = moment(endDate || startDate).add(1, 'ms').toDate();
const rangeDate = _.range(rangeDateStart, rangeDateLimit, 1000 * 60 * 60 * 24).map(ts=>moment(ts).toDate());
return Promise.reduce(rangeDate, async (r, date) => r.concat(await rank_like_per_date(date)), []);
}
async function rank_like_per_date(startDate) {
const uri = new URL('https://blog.stat.naver.com/api/blog/rank/likePc?timeDimension=DATE&startDate=&exclude=');
uri.searchParams.set('startDate', moment(startDate).format('YYYY-MM-DD'));
const res = await fetch(uri).then(r=>r.json());
const statDataList = _.get(res, 'result.statDataList', []);
return statDataList.reduce((r, item) => {
const columnInfo = _.get(item, 'data.columnInfo', []);
const rows = _.get(item, 'data.rows', { rank: [] });
_.map(rows.rank, (rank, offset) => {
const values = columnInfo.map((column)=>_.chain(rows).get(column).nth(offset).value());
const item = _.zipObject(columnInfo, values);
item.createDate = moment(item.createDate, 'YYYY.MM.DD. HH.mm').toISOString(true);
item.date = moment(item.date, 'YYYY-MM-DD').toISOString(true);
r.push(item);
});
return r;
}, []);
}
window.rank_like = rank_like;
window.rank_like_per_date = rank_like_per_date;
})
await inject_js(() => {
async function likes(logNo, pageNo = 1, results = []) {
const blogId = new URL(location.href).searchParams.get('blogId') || location.pathname.split('/')[1];
const ref = new URL('https://m.blog.naver.com/SympathyHistoryList.nhn?blogId=&logNo=&categoryId=POST');
ref.searchParams.set('blogId', blogId);
ref.searchParams.set('logNo', logNo);
const uri = new URL('https://m.blog.naver.com/rego/SympathyHistoryListJson.nhn?blogId=&logNo=&pageNo=&categoryId=POST');
uri.searchParams.set('blogId', blogId);
uri.searchParams.set('logNo', logNo);
uri.searchParams.set('pageNo', pageNo);
const resp = await GM_xmlhttpRequest({ url: uri.toString(), headers: { 'referer': ref.toString() } });
const res = JSON.parse(resp.responseText.replace(/^[\]\)\]\}\'\,\s\r\n]+/, ''));
const totalPage = _.get(res, 'result.totalPage', 1);
const sympathyHistoryList = _.get(res, 'result.sympathyHistoryList', []);
results.push(...sympathyHistoryList);
return (totalPage > pageNo) ? likes(logNo, pageNo + 1, results) : results;
}
window.likes = likes;
})
await inject_js(() => {
const html = `
네이버 블로그 공감수 순위 어드밴스드
{{ date.substr(0, 10) }} |
순위 |
제목 |
공감수 |
타입 |
작성일 |
기능 |
{{ row.rank }} |
{{ row.title }} |
{{ row.event }} |
{{ row.type }} |
{{ row.createDate.substr(0, 10) }} |
|
닉네임 (아이디) |
등록일 |
{{ like.userNickName }} ({{like.userId}})
|
{{ like.addDate }} |
|
`;
const $window = window.open('about:blank', '_likes_window', 'width=960,height=720');
setTimeout(async ()=>{
$window.document.write(html);
setTimeout(async () => {
$window.document.dispatchEvent(new CustomEvent('append.start'));
$window.document.dispatchEvent(new CustomEvent('append.finish'));
}, 300);
}, 300);
})
});