@@ -3,7 +3,7 @@ layout: base | |||
--- | |||
<div id="header"> | |||
<h1 class="naked">Hi, I'm <span class="text-highlight">Earwig</span>!</h1> | |||
<h1 id="header">Hi, I'm <span class="color-highlight">Earwig</span>!</h1> | |||
</div> | |||
<div id="content"> | |||
<table> | |||
@@ -51,7 +51,7 @@ layout: base | |||
{{ content }} | |||
</td> | |||
<td id="right-box"> | |||
<h2 class="topless">Posts</h2> | |||
<h2 id="posts">Posts</h2> | |||
<ul> | |||
{% for post in site.posts %} | |||
<li class="post">{{ post.date | date: "%b %d, %Y" }}: <a class="invert" href="{{ post.url }}">{{ post.title }}</a><br /><span class="description">{{ post.description }}</span></li> | |||
@@ -3,10 +3,12 @@ layout: base | |||
--- | |||
<div id="header"> | |||
<h1 class="naked"><a class="incognito" href="/">{{ page.title }}</a></h1> | |||
<h1 id="header"><a class="incognito" href="/">{{ page.title }}</a></h1> | |||
</div> | |||
<div id="content"> | |||
<span class="description"><span class="text-highlight">Date:</span> {{ page.date | date: "%b %d, %Y" }}</span> | |||
<div id="post-info" class="description"> | |||
<span class="color-highlight">Date:</span> {{ page.date | date: "%b %d, %Y" }} | |||
</div> | |||
<div id="post"> | |||
{{ content }} | |||
</div> | |||
@@ -0,0 +1,134 @@ | |||
--- | |||
layout: post | |||
title: EarwigBot Progress: Wiki Toolset | |||
description: YAWTF (Yet Another Wiki Tools Framework, or Yet Another... WTF?) | |||
--- | |||
So I've been spending the past week and a half working on EarwigBot's new | |||
wikitools framework thing (to avoid confusion with Mr.Z-man's | |||
`python-wikitools` package, I'm referring to it as "EarwigBot's Wiki Toolset" | |||
in the docs, even though it's `wiki.tools` internally). Basically, it's the | |||
interface between EarwigBot and the MediaWiki API. | |||
As Josh put it, this is "the thing that actually makes it work". | |||
So, now you can do this (from within Python's interpreter, a wiki bot task, or | |||
an IRC command): | |||
{% highlight pycon %} | |||
>>> from wiki import tools | |||
>>> site = tools.get_site() | |||
>>> print site.name() | |||
enwiki | |||
>>> print site.project() | |||
wikipedia | |||
>>> print site.lang() | |||
en | |||
>>> print site.domain() | |||
en.wikipedia.org | |||
{% endhighlight %} | |||
Our `config.json` file stores site information, along with our chosen "default | |||
site". Pretty neat, huh? "But what can it actually do?" I hear you ask? Well, | |||
for example, we can get information about users: | |||
{% highlight pycon %} | |||
>>> user = site.get_user("The Earwig") | |||
>>> print user.editcount() | |||
11079 | |||
>>> print user.groups() | |||
[u'*', u'user', u'autoconfirmed', u'abusefilter', u'sysop'] | |||
>>> reg = user.registration() | |||
>>> import time | |||
>>> print time.strftime("%a, %d %b %Y %H:%M:%S", reg) | |||
Thu, 03 Jul 2008 21:51:34 | |||
{% endhighlight %} | |||
and pages as well, with intelligent namespace logic: | |||
{% highlight pycon %} | |||
>>> page = site.get_page("Wikipedia:Articles for creation") | |||
>>> print page.url() | |||
http://en.wikipedia.org/wiki/Wikipedia:Articles_for_creation | |||
>>> print page.namespace() | |||
4 | |||
>>> print site.namespace_id_to_name(4) | |||
Wikipedia | |||
>>> print site.namespace_id_to_name(4, all=True) | |||
[u'Wikipedia', u'Project', u'WP'] | |||
>>> print page.is_talkpage() | |||
False | |||
>>> talkpage = page.toggle_talk() | |||
>>> print talkpage.title() | |||
Wikipedia talk:Articles for creation | |||
>>> print talkpage.is_talkpage() | |||
True | |||
{% endhighlight %} | |||
and with support for redirect following: | |||
{% highlight pycon %} | |||
>>> page = site.get_page("Main page") | |||
>>> print page.is_redirect() | |||
True | |||
>>> print page.get() | |||
#REDIRECT [[Main Page]] | |||
[[Category:Protected redirects]] | |||
[[Category:Main Page| ]] | |||
>>> print page.get_redirect_target() | |||
Main Page | |||
>>> page = site.get_page("Main page", follow_redirects=True) | |||
>>> print page.is_redirect() | |||
False # would only be True if "Main page" is a double redirect | |||
>>> print page.get() | |||
<!-- BANNER ACROSS TOP OF PAGE --> | |||
{| id="mp-topbanner" style="width:100%; background:#f9f9f9; margin:1.2em 0 6px 0; border:1px solid #ddd;" | |||
| style="width:61%; color:#000;" | | |||
... | |||
{% endhighlight %} | |||
Of course, a Wiki Toolset would be nothing without login! Our username and | |||
password are stored (encrypted with Blowfish) in the bot's `config.json` file, | |||
and we login automatically whenever we create a new Site object – unless | |||
we're already logged in, of course, and we know that based on whether we have | |||
valid login cookies. | |||
{% highlight pycon %} | |||
>>> user = site.get_user() # gets the logged-in user | |||
>>> print user.name() | |||
EarwigBot | |||
{% endhighlight %} | |||
Cookies are stored in a special `.cookies` file in the project root (with no | |||
access given to other users, of course). We support both per-project login and | |||
CentralAuth, meaning I can do... | |||
{% highlight pycon %} | |||
>>> es = tools.get_site("eswiki") | |||
>>> print es.get_user().name() | |||
EarwigBot | |||
{% endhighlight %} | |||
without making additional logins. One thing I strove for when designing the | |||
toolset was as minimal API usage as possible – we accept gzipped data, we | |||
don't make API queries unless they're actually requested, and we combine | |||
queries whenever possible. Of course, I'm probably doing it all wrong, but | |||
it seems to be working so far. | |||
So... yeah. Carry on then! | |||
:—earwig |
@@ -5,30 +5,31 @@ body { | |||
background-color: #E0E0E0; | |||
} | |||
.text-highlight { | |||
.color-highlight { | |||
color: #040; | |||
} | |||
.description { | |||
font-size: 12px; | |||
} | |||
.topless { | |||
margin-top: 0px; | |||
padding-top: 0px; | |||
.highlight { /* syntax highlighter */ | |||
background: #f2f2f2; | |||
border: 1px solid #e8e8e8; | |||
border-radius: 10px; | |||
padding-left: 16px; | |||
line-height: 1.35em; | |||
font-size: 13px; | |||
} | |||
.naked { | |||
margin-top: 0px; | |||
padding-top: 0px; | |||
margin-bottom: 0px; | |||
padding-bottom: 0px; | |||
.description { | |||
font-size: 12px; | |||
} | |||
h1, h2 { | |||
text-align: center; | |||
} | |||
pre { | |||
white-space: pre-wrap; | |||
} | |||
div.project { | |||
border: 1px solid #CCC; | |||
border-radius: 5px; | |||
@@ -47,12 +48,12 @@ div.project-body { | |||
} | |||
td.about-l { | |||
padding: 3px 6px 3px 6px; | |||
padding: 4px 12px 4px 12px; | |||
border-left: 1px solid #CCC; | |||
} | |||
td.about-r { | |||
padding: 3px 6px 3px 6px; | |||
padding: 4px 12px 4px 12px; | |||
border-right: 1px solid #CCC; | |||
} | |||
@@ -65,17 +66,29 @@ td.dark-l { background-color: #DADADA; } | |||
td.light-r { background-color: #F7F7F7; } | |||
td.dark-r { background-color: #E5E5E5; } | |||
h1#header { | |||
margin-top: 0px; | |||
padding-top: 0px; | |||
margin-bottom: 0px; | |||
padding-bottom: 0px; | |||
} | |||
h2#posts { | |||
margin-top: 0px; | |||
padding-top: 0px; | |||
} | |||
div#container { | |||
width: 800px; | |||
margin: 16px auto 16px auto; | |||
margin: 20px auto 32px auto; | |||
border: 1px solid #999; | |||
border-radius: 10px; | |||
background-color: #FFF; | |||
} | |||
div#header { | |||
margin: 12px 12px 20px 12px; | |||
padding: 15px 0px 15px 0px; | |||
margin: 16px 16px 20px 16px; | |||
padding: 30px 0px 30px 0px; | |||
border: 1px solid #999; | |||
border-radius: 10px 10px 0px 0px; | |||
background-color: #DED; | |||
@@ -88,10 +101,14 @@ div#content { | |||
div#footer { | |||
font-size: 11px; | |||
text-align: center; | |||
padding: 6px 2px 6px 2px; | |||
padding: 9px 4px 12px 4px; | |||
color: #222; | |||
} | |||
div#post-info { | |||
margin-left: 24px; | |||
} | |||
div#post { | |||
line-height: 1.5em; | |||
} | |||
@@ -1,10 +1,9 @@ | |||
/* | |||
This file has been shamelessly stolen from: | |||
This file has been shamelessly stolen from (with modifications): | |||
https://github.com/mojombo/tpw/blob/master/css/syntax.css | |||
...which is released under the MIT license. | |||
*/ | |||
.highlight { background: #ffffff; } | |||
.highlight .c { color: #999988; font-style: italic } /* Comment */ | |||
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ | |||
.highlight .k { font-weight: bold } /* Keyword */ | |||
@@ -20,7 +19,7 @@ This file has been shamelessly stolen from: | |||
.highlight .gh { color: #999999 } /* Generic.Heading */ | |||
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ | |||
.highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */ | |||
.highlight .go { color: #888888 } /* Generic.Output */ | |||
.highlight .go { color: #666666 } /* Generic.Output */ | |||
.highlight .gp { color: #555555 } /* Generic.Prompt */ | |||
.highlight .gs { font-weight: bold } /* Generic.Strong */ | |||
.highlight .gu { color: #aaaaaa } /* Generic.Subheading */ | |||