Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save motemen/163197 to your computer and use it in GitHub Desktop.
Save motemen/163197 to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name Hatena::Group: Recent Entries
// @namespace http://lowreal.net/
// @include https://*.g.hatena.ne.jp/
// @include http://*.g.hatena.ne.jp/
// @require http://svn.coderepos.org/share/lang/javascript/jsdeferred/trunk/jsdeferred.userscript.js
// @require http://gist.github.com/3239.txt#createElementFromString
// @require http://gist.github.com/46391.txt#duration
// @require http://gist.github.com/120040.txt#ambtime
// ==/UserScript==
$E = createElementFromString;
(function () { with (D()) {
// 10 件表示する
var count = 10;
var recent = [];
var ns = {
"rdf" : "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
"rss" : "http://purl.org/rss/1.0/",
"dc" : "http://purl.org/dc/elements/1.1/",
"content" : "http://purl.org/rss/1.0/modules/content/"
};
function $XR (exp, context, type /* want type */) {
if (typeof context == "function") {
type = context;
context = null;
}
if (!context) context = document;
exp = (context.ownerDocument || context).createExpression(exp, function (prefix) {
return ns[prefix];
});
switch (type) {
case String: return exp.evaluate(context, XPathResult.STRING_TYPE, null).stringValue;
case Number: return exp.evaluate(context, XPathResult.NUMBER_TYPE, null).numberValue;
case Boolean: return exp.evaluate(context, XPathResult.BOOLEAN_TYPE, null).booleanValue;
case Array:
var result = exp.evaluate(context, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
for (var ret = [], i = 0, len = result.snapshotLength; i < len; i++) {
ret.push(result.snapshotItem(i));
}
return ret;
case undefined:
var result = exp.evaluate(context, XPathResult.ANY_TYPE, null);
switch (result.resultType) {
case XPathResult.STRING_TYPE : return result.stringValue;
case XPathResult.NUMBER_TYPE : return result.numberValue;
case XPathResult.BOOLEAN_TYPE: return result.booleanValue;
case XPathResult.UNORDERED_NODE_ITERATOR_TYPE:
// not ensure the order.
var ret = [], i = null;
while ((i = result.iterateNext())) ret.push(i);
return ret;
}
return null;
default: throw(TypeError("$X: specified type is not valid type."));
}
}
var container = $E("<div />");
var main = document.querySelector("div.main") || document.querySelector("div.hatena-body");
main.insertBefore(container, main.firstChild);
var title = $E("<div class='recentitem_diary'>最新エントリ <span class='status'></span></div>");
container.appendChild(title);
with (title.style) {
fontWeight = "bold";
}
with (title.status.style) {
fontSize = "80%";
}
var num = 1;
function addEntry (entry) {
entry.num = num++;
console.log(entry);
var date = entry.date;
var m = date.match(/(\d\d\d\d)-(\d\d)-(\d\d)(?:T(\d\d):(\d\d):(\d\d))?/);
var d = m[4] ? new Date(+m[1], +m[2] - 1, +m[3], +m[4], +m[5], +m[6])
: new Date(+m[1], +m[2] - 1, +m[3]);
entry.ambdate = ambtime(d);
var e = $E(<><![CDATA[
<div class="day">
<h2>
<a href="#{link}">#{num}: <span class="title">#{title}</span></a>
<a href="/#{creator}/" style="font-size: 80%"><span class="title">id:#{creator}</span></a>
<div class="date" style="font-size: 80%; text-align: right">#{ambdate} #{date}</div>
</h2>
<div class="body">
<div class="section">
</div>
</div>
</div>
]]></>.toString(), {
parent: container,
data : entry
});
if (entry.encoded) {
e.body.innerHTML = entry.encoded;
} else {
e.section.innerHTML = entry.content;
}
}
// [1]
// 1, 2, 5
// [3]
// 3, 4
// [6]
// 6
//
// エントリフィードを1つとってくる
// エントリリストにうち、エントリフィード最新より新しいエントリは確定
// 確定したエントリが n に達したら終了
http.get("/diarylist?mode=rss").
next(function (req) {
var diarylist = $XR("/rdf:RDF/rss:item", req.responseXML);
var entries = [], loadedNum = 0;
return loop(diarylist.length, function (i) {
var item = diarylist[i];
var about = item.getAttributeNS(ns.rdf, "about").replace(/^https?:/, location.protocol);
var rss = about + "rss";
var date = $XR("string(dc:date)", item);
if (rss.match(/\/hatena\w+\//)) return null; // skip;
entries = entries.filter(function (e) {
if (e.date > date) {
addEntry(e);
loadedNum++;
return false;
} else {
return true;
}
});
if (loadedNum >= count) {
throw "done";
}
title.status.innerHTML = "Fixed: " + loadedNum + " Requesting Next... " + rss;
return http.get(rss).next(function (req) {
var entrylist = $XR("/rdf:RDF/rss:item", req.responseXML);
for (var i = 0, len = entrylist.length; i < len; i++) {
var entry = entrylist[i];
entries.push({
title: $XR("string(rss:title)", entry),
link: $XR("string(rss:link)", entry),
date: $XR("string(dc:date)", entry),
creator: $XR("string(dc:creator)", entry),
content: $XR("string(rss:description)", entry),
encoded: $XR("string(content:encoded)", entry)
});
}
entries = entries.sort(function (a, b) {
if (a.date < b.date) return 1;
if (a.date > b.date) return -1;
return 0;
});
});
}).
next(function () {
while (entries.length && loadedNum < count) {
addEntry(entries.shift());
loadedNum++;
}
}).
error(function (e) {
if (e != "done") throw e;
}).
next(function () {
location.href = 'javascript:' + uneval(function () {
Hatena.Star.SiteConfig = {
entryNodes: {
'div.day': {
uri: 'h2 a',
title: 'h2',
container: 'h2'
}
}
};
new Hatena.Star.EntryLoader();
}) + '()';
title.status.innerHTML = "";
})
}).
error(function (e) {
alert(e);
});
} })();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment