/* * @title backup Hatena Space * @description backup Hatena Space. see http://a-kuma3.hatenablog.com/entry/hatena_space_backup * @include http://space.hatena.ne.jp/* * @license MIT License */ (function(){ /* [OPTIONS] only_my_entry: remove other users posts. need login. expand_hatena_star: slower 10-50% to exract. larger 10% or more. embed_stylesheet: need 218 KB more. */ var opt = { only_my_entry: false, expand_hatena_star: false, embed_stylesheet: true, }; // check location re_check = new RegExp("^http://space\.hatena\.ne\.jp/~/\\d+/\\d+#?$"); if (! re_check.test(location.href)) { console.log('"' + location.href + '"'); alert("use at topics page @ space.hatena.ne.jp."); return; } var hspace_pages = []; var hspace_stylesheet = ""; var hspace_title = ""; var need_break = false; var is_last_page = false; var page = 1; var max_page = -1; var last_entry_number = -1; var d_ = document; var b_ = d_.body; var style_url = "http://space.hatena.ne.jp/css/master.css?47ab9942"; var t_start = new Date(); function setStyle(target, prop) { for (k in prop) { target.style[k] = prop[k]; } } function removeNode(e) { e.parentNode.removeChild(e); } function $id(id) { return d_.getElementById(id); } function createProgressView() { if ($id("progress")) { removeNode($id("progress").parentNode); } var panel = d_.createElement("DIV"); setStyle(panel, { display: "inline-block", position: "fixed", top: "1ex", right: "1ex", backgroundColor: "green", border: "2px inset darkgreen", color: "white", padding: "0.5ex 2ex", zIndex: 1000, }); var m = d_.createElement("DIV"); m.id = "progress"; m.innerHTML = " "; panel.appendChild(m); var btn = d_.createElement("BUTTON"); btn.innerHTML = "BREAK"; btn.style.marginTop = "0.5em"; btn.onclick = function() { need_break = true; }; panel.appendChild(btn); b_.appendChild(panel); } var xhr = new XMLHttpRequest(); xhr.onload = function(e) { if (e.target.status <= 200) { treatResponse(e.target.response); } }; function is_spam(entry) { /* TODO: another spam pattern */ var re = new RegExp("^https?://\\S+$"); if (re.test(entry.textContent)) { return true; } return false; } function treatResponse(resp) { hspace_title = resp.querySelector("head title").innerHTML; var entries = resp.querySelector("div#entries"); if (max_page == -1) { var last_entry = entries.querySelector("div.entry"); last_entry_number = parseInt(last_entry.dataset.entryNumber, 10); max_page = Math.ceil(last_entry_number / 20.0); } // remove entries of other users if (opt.only_my_entry) { try { var myid = resp.documentElement.dataset.userName; var re = new RegExp("/" + myid + "/$"); Array.from(entries.querySelectorAll("div.entry div.author > a[href]")).forEach(function(e) { if (! re.test(e.href)) { removeNode(e.parentNode.parentNode.parentNode); } }); } catch (ex) { console.error("ERROR: " + e.target.responseURL); console.error(ex); } } // remove spam entries Array.from(entries.querySelectorAll("div.entry > div.body > div.plain")).forEach(function(e) { if (is_spam(e)) { console.log("maybe spam: " + e.parentNode.parentNode.querySelector("div.author").textContent.replace(/\s/g, "")); removeNode(e.parentNode.parentNode); } }); // change user link space to profile of user { var sel = [ "a.author-image-link", "div.meta > .author > a", "ul.comment-list > li > a", "ul.comment-list > li > .user-comment > a", "a.id-call", ].join(","); Array.from(entries.querySelectorAll(sel)).forEach(function(e) { e.href = e.href.replace(/space\.hatena\.ne\.jp/, "profile.hatena.ne.jp"); }); } // display all comments Array.from(entries.querySelectorAll("div.comments > ul.comment-list li.hide")).forEach(function(e) { e.classList.remove("hide"); }); // remove node (reduce size) { var sel = [ // post form "div.comments > form.post-comment", "div.reply-action > form.quick-reply", // action element "div.comments > a.expand-comments", "ul.comment-list li div.comment-data > a.delete-comment", "div.reply-action > a.open-entry-menu", "div.reply-action > ul.entry-menu", // star button "div.reply-action button.star-add-button", ].join(","); Array.from(entries.querySelectorAll(sel)).forEach(function(e) { removeNode(e); }); } // Hatena Star if (opt.expand_hatena_star) { var keys = []; Array.from(entries.querySelectorAll(".star-list-container")).forEach(function(e) { keys.push(e.dataset.resourceKey); }); var url = "http://space.hatena.ne.jp/-/api/star?" + keys.map(function(e) { return "resource_key[]=" + e; }).join("&"); var xx = new XMLHttpRequest(); xx.open('GET', url, true); xx.onload = (function() { var ec = entries; return function(ev) { var a; eval("a=" + ev.target.responseText); a.resources.forEach(function(e) { //console.log(e); e.stars.forEach(function(ee) { var stcn = ec.querySelector('span.star-list-container[data-resource-key="' + ee.resource_key + '"]'); var box = d_.createElement("span"); box.className = "star-box"; box.style.backgroundImage="url(" + ee.user.profile_image + ")"; var img = d_.createElement("a"); img.className = "star-image"; img.href = "http://s.hatena.ne.jp" + ee.user.path; img.innerHTML = ee.user.name; box.appendChild(img); stcn.appendChild(box); }); }); if (is_last_page) { finishLoading(); } }; })(); xx.send(null); } else { var sel = [ "div.reply-action div.star-container", ].join(","); Array.from(entries.querySelectorAll(sel)).forEach(function(e) { removeNode(e); }); } // post time Array.from(entries.querySelectorAll("time")).forEach(function(e) { function d2(n) { return n < 10 ? "0"+n : n; } var t = new Date(parseInt(e.dataset.epochMilliseconds)); e.innerHTML = t.getFullYear() + "/" + d2(t.getMonth()+1) + "/" + d2(t.getDate()) + " " + d2(t.getHours()) + ":" + d2(t.getMinutes()) + ":" + d2(t.getSeconds()); }); hspace_pages.push(entries); if (need_break) { $id("progress").innerHTML = "BREAK Loading !"; return; } is_last_page = !resp.querySelector("#timeline-pager-loading"); if (is_last_page) { $id("progress").innerHTML = "FINISH Loading"; if (! opt.expand_hatena_star) { setTimeout(finishLoading, 0); } } else { page += 1; loadEntries(); } } function finishLoading() { console.log("*** FINISH ***"); displayResultView(); console.log("display initialized"); displaySource(); console.log("source displayed"); var lapse = (new Date().getTime() - t_start.getTime()) / 1000; console.log("=== COMPLETE === " + [ lapse + " sec", max_page + " pages", last_entry_number + " posts", ].join(", ")); } function displayResultView() { b_.innerHTML = ""; b_.classList.remove("new-space"); // source area var sourceArea = d_.createElement("div"); setStyle(sourceArea, { display: "inline-block", width: "20em", padding: "0.5ex 2ex", backgroundColor: "palegoldenrod", verticalAlign: "top", }); function createUnitArea(dest, title, id, viewtype) { var e_txt = d_.createElement("textarea"); e_txt.id = "source-" + id; e_txt.rows = 5; setStyle(e_txt, { width: "100%", display: "block", }); var e_title = d_.createElement("a"); e_title.innerHTML = title; e_title.href = "#"; setStyle(e_title, { display: "block", textDecoration: "underline", borderLeft: "1em solid saddlebrown", paddingLeft: "1ex", marginTop: "0.5ex", }); e_title.onclick = function() { var viewArea = $id("view-area"); var dd_ = viewArea.contentWindow.document; dd_.open(viewtype, "replace"); // dd_.charset = "Shift_JIS"; dd_.write(this.nextSibling.value); dd_.close(); return false; }; dest.appendChild(e_title); dest.appendChild(e_txt); } createUnitArea(sourceArea, "entries HTML" , "entries" , "text/html"); createUnitArea(sourceArea, "style sheet" , "stylesheet", "text/plain"); createUnitArea(sourceArea, "images URL list", "imagelist" , "text/plain"); createUnitArea(sourceArea, "images HTML" , "imagepage" , "text/html"); b_.appendChild(sourceArea); // preview frame var viewArea = d_.createElement("iframe"); viewArea.id = "view-area"; setStyle(viewArea, { width: "600px", height: window.innerHeight + "px", display: "inline-block", verticalAlign: "top", }); b_.appendChild(viewArea); } function code_stylesheet() { var code = [ '', '', ].join("\n"); if (opt.embed_stylesheet) { code = [ '', ].join("\n"); } var star_image = [ "", ].join("\n"); return code + star_image; } function displaySource() { // contents var e = $id("source-entries"); e.value = [].concat([ "", "", '
', '', '