2013-03-29 10:01:04 +00:00
|
|
|
#!/usr/bin/env python
|
2013-04-09 17:33:50 +00:00
|
|
|
# -*- coding: iso-8859-1 -*-
|
2014-01-05 15:50:57 +00:00
|
|
|
# Copyright (C) 2012-2014 Bastian Kleineidam
|
2013-03-29 10:01:04 +00:00
|
|
|
from __future__ import print_function
|
|
|
|
import sys
|
|
|
|
import os
|
|
|
|
import time
|
|
|
|
import cgi
|
|
|
|
import codecs
|
2013-04-09 17:33:50 +00:00
|
|
|
import json
|
2013-03-29 10:01:04 +00:00
|
|
|
sys.path.append(os.path.join(os.path.dirname(__file__), ".."))
|
|
|
|
from dosagelib.scraper import get_scraperclasses
|
|
|
|
from dosagelib.util import getLangName
|
|
|
|
|
|
|
|
|
|
|
|
class Status:
|
|
|
|
"""Status of a comic strip."""
|
|
|
|
ok = u"ok"
|
|
|
|
error = u"error"
|
|
|
|
|
|
|
|
comicdata_template = u"""
|
|
|
|
/* generated on %(date)s */
|
|
|
|
$(document).ready(function() {
|
|
|
|
$('#comics').html('<table cellpadding="0" cellspacing="0" border="0" class="display" id="comictable"></table>');
|
|
|
|
$('#comictable').dataTable( {
|
|
|
|
"aaData": [
|
|
|
|
%(content)s
|
|
|
|
],
|
|
|
|
"aoColumns": [
|
|
|
|
{ "sTitle": "Name" },
|
|
|
|
{ "sTitle": "Genre" },
|
|
|
|
{ "sTitle": "Language" },
|
2013-04-09 17:33:50 +00:00
|
|
|
{ "sTitle": "Status" },
|
|
|
|
{ "sTitle": "Votes" }
|
2013-03-29 10:01:04 +00:00
|
|
|
]
|
|
|
|
} );
|
|
|
|
} );
|
|
|
|
"""
|
|
|
|
|
|
|
|
comic_template = u"""\
|
2013-04-09 17:33:50 +00:00
|
|
|
title: %(name)s
|
2013-04-24 18:25:42 +00:00
|
|
|
url: "/comics/%(pageurl)s"
|
2013-03-29 10:01:04 +00:00
|
|
|
---
|
|
|
|
Dosage comic %(name)s
|
|
|
|
-----------------------------------------
|
|
|
|
|
2013-04-24 18:25:42 +00:00
|
|
|
<p id="msg"></p>
|
|
|
|
<script type="text/javascript">
|
|
|
|
if (window.location.search === '?edit_info_mail=sent_ok') {
|
|
|
|
var elem = document.getElementById("msg");
|
2013-04-29 18:24:40 +00:00
|
|
|
elem.innerHTML = 'Edited information sucessfully sent for review, which is usually done daily. Thanks!';
|
2013-04-24 18:25:42 +00:00
|
|
|
elem.className = 'ok';
|
|
|
|
}
|
|
|
|
</script>
|
2013-03-29 10:01:04 +00:00
|
|
|
<table class="comicinfo">
|
|
|
|
<tr>
|
|
|
|
<th>Description</th><td>%(description)s</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<th>Website</th><td><a href="%(url)s">%(url)s</a></td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<th>Genre</th><td>%(genre)s</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<th>Language</th><td>%(language)s</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<th>Adult content</th><td>%(adult)s</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<th>Status</th><td>%(status)s on %(date)s</td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
2013-12-05 19:45:13 +00:00
|
|
|
<th>Votes</th><td>%(vote)s
|
|
|
|
<form action="http://gaecounter.appspot.com/count/" method="POST">
|
|
|
|
<input name="name" type="hidden" value="%(votename)s"/>
|
|
|
|
<input name="uid" type="hidden" id="voteuid" value=""/>
|
|
|
|
<input type="submit" value="Vote"/>
|
|
|
|
</form>
|
|
|
|
</td>
|
2013-03-29 10:01:04 +00:00
|
|
|
</tr>
|
|
|
|
</table>
|
2013-12-05 19:45:13 +00:00
|
|
|
<script type="text/javascript">
|
|
|
|
var ua = navigator.userAgent;
|
|
|
|
document.getElementById("voteuid").value = ua.replace(/[^a-zA-Z0-9\._:]/g , "_");;
|
|
|
|
</script>
|
2013-04-16 17:53:12 +00:00
|
|
|
|
2013-04-23 19:51:22 +00:00
|
|
|
[Edit this info](%(editurl)s) or go back to the [comic list](../comic-index.html).
|
|
|
|
"""
|
|
|
|
|
|
|
|
comic_edit_template = u"""\
|
|
|
|
title: Edit %(name)s
|
2013-04-24 18:25:42 +00:00
|
|
|
url: "/comics/%(editurl)s"
|
2013-04-23 19:51:22 +00:00
|
|
|
---
|
|
|
|
Edit info for comic %(name)s
|
|
|
|
|
2013-04-24 18:25:42 +00:00
|
|
|
<form name="comic" action="http://gaepostmail.appspot.com/comic/" method="post">
|
2013-04-23 19:51:22 +00:00
|
|
|
<table class="comicinfo">
|
|
|
|
<tr>
|
2013-04-24 18:25:42 +00:00
|
|
|
<th>Description</th><td><textarea name="description" cols="40" rows="3">%(description)s</textarea></td>
|
2013-04-23 19:51:22 +00:00
|
|
|
</tr>
|
|
|
|
<tr>
|
2013-04-24 18:25:42 +00:00
|
|
|
<th>Website</th><td><input type="text" name="url" value="%(url)s" size="40"/></td>
|
2013-04-23 19:51:22 +00:00
|
|
|
</tr>
|
|
|
|
<tr>
|
2013-04-24 18:25:42 +00:00
|
|
|
<th>Genre</th><td><input type="text" name="genre" value="%(genre)s" size="40"/></td>
|
2013-04-23 19:51:22 +00:00
|
|
|
</tr>
|
|
|
|
<tr>
|
2013-04-24 18:25:42 +00:00
|
|
|
<th>Language</th><td><input type="text" name="language" value="%(language)s" size="40"/></td>
|
2013-04-23 19:51:22 +00:00
|
|
|
</tr>
|
|
|
|
<tr>
|
|
|
|
<th>Adult content</th><td><input type="checkbox" name="adult" value="adult" %(adultchecked)s/></td>
|
|
|
|
</tr>
|
|
|
|
<tr>
|
2013-04-24 18:25:42 +00:00
|
|
|
<th></th><td>
|
|
|
|
<input type="hidden" name="comic" value="%(comic)s" />
|
|
|
|
<input type="submit" name="submit" value="Submit" />
|
|
|
|
</td>
|
2013-04-23 19:51:22 +00:00
|
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
</form>
|
|
|
|
|
|
|
|
Back to the [comic](%(pageurl)s).
|
2013-03-29 10:01:04 +00:00
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
def get_mtime (filename):
|
|
|
|
"""Return modification time of filename."""
|
|
|
|
return os.path.getmtime(filename)
|
|
|
|
|
|
|
|
|
|
|
|
def strdate(t):
|
|
|
|
"""Get formatted date string."""
|
|
|
|
return time.strftime("%d.%m.%Y", time.localtime(t))
|
|
|
|
|
|
|
|
|
|
|
|
def get_testscraper(line):
|
|
|
|
"""Get scraper from test output line."""
|
|
|
|
classname = line.split('::')[1][4:]
|
|
|
|
for scraperclass in get_scraperclasses():
|
|
|
|
if scraperclass.__name__ == classname:
|
|
|
|
return scraperclass
|
|
|
|
raise ValueError("Scraper %r not found" % classname)
|
|
|
|
|
|
|
|
|
|
|
|
def get_testinfo(filename, modified):
|
|
|
|
"""Maintains a static list of comics which users can vote on.
|
|
|
|
@return: {name -> {
|
|
|
|
"status": Status.*,
|
|
|
|
"url": string,
|
|
|
|
"description": string,
|
|
|
|
"error": string or None,
|
|
|
|
"genre": string,
|
|
|
|
"language": string,
|
|
|
|
"adult": bool,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
"""
|
|
|
|
testinfo = {}
|
|
|
|
with open(filename, "r") as f:
|
|
|
|
print("Tests parsed: 0", end=" ", file=sys.stderr)
|
|
|
|
num_tests = 0
|
|
|
|
add_error = False
|
|
|
|
keys = []
|
|
|
|
for line in f:
|
|
|
|
try:
|
|
|
|
if line.startswith((". ", "F ")) and "test_comics" in line:
|
|
|
|
add_error = line.startswith("F ")
|
|
|
|
num_tests += 1
|
|
|
|
key, entry = get_testentry(line)
|
|
|
|
keys.append(key)
|
|
|
|
update_testentry(key, entry, testinfo)
|
|
|
|
if num_tests % 5 == 0:
|
|
|
|
print(num_tests, end=" ", file=sys.stderr)
|
|
|
|
elif add_error and line.startswith(" E "):
|
|
|
|
entry["error"] = line[3:].strip()
|
|
|
|
except ValueError as msg:
|
|
|
|
print(msg)
|
|
|
|
return testinfo
|
|
|
|
|
|
|
|
|
|
|
|
def get_testentry(line):
|
|
|
|
"""Get one test entry."""
|
|
|
|
scraper = get_testscraper(line)
|
|
|
|
key = scraper.__name__
|
|
|
|
name = scraper.getName()
|
|
|
|
if len(name) > 40:
|
|
|
|
name = name[:37] + u"..."
|
2013-04-09 17:33:50 +00:00
|
|
|
genres = u",".join(sorted(scraper.genres))
|
2013-03-29 10:01:04 +00:00
|
|
|
if isinstance(scraper.description, unicode):
|
|
|
|
desc = scraper.description
|
|
|
|
else:
|
|
|
|
desc = scraper.description.decode("utf-8", "ignore")
|
2013-05-08 05:11:57 +00:00
|
|
|
if not desc:
|
|
|
|
desc = u'-'
|
2013-03-29 10:01:04 +00:00
|
|
|
entry = {
|
|
|
|
"status": Status.ok if line.startswith(u". ") else Status.error,
|
|
|
|
"name": name,
|
|
|
|
"url": scraper.url,
|
|
|
|
"description": desc,
|
|
|
|
"genre": genres,
|
|
|
|
"language": getLangName(scraper.lang),
|
|
|
|
"error": None,
|
|
|
|
"adult": scraper.adult,
|
2013-04-09 17:33:50 +00:00
|
|
|
"vote": get_vote(name),
|
2013-03-29 10:01:04 +00:00
|
|
|
}
|
|
|
|
return key, entry
|
|
|
|
|
|
|
|
|
|
|
|
def update_testentry(key, entry, testinfo):
|
|
|
|
"""Update one entry with testinfo information."""
|
|
|
|
testinfo[key] = entry
|
|
|
|
|
|
|
|
|
2013-04-09 17:33:50 +00:00
|
|
|
_votes = None
|
|
|
|
def get_vote(name):
|
|
|
|
global _votes
|
|
|
|
if _votes is None:
|
|
|
|
fname = os.path.join('data', 'votes.json')
|
|
|
|
with open(fname, 'rb') as f:
|
|
|
|
_votes = json.load(f)
|
|
|
|
key = name.replace('/', '_')
|
|
|
|
return _votes.get(key, 0)
|
|
|
|
|
|
|
|
|
2013-03-29 10:01:04 +00:00
|
|
|
def get_comicdata(testinfo):
|
|
|
|
"""Get comic data for table listing."""
|
|
|
|
rows = []
|
|
|
|
for key in sorted(testinfo.keys()):
|
|
|
|
entry = testinfo[key]
|
|
|
|
url = "comics/%s.html" % key
|
|
|
|
args = {
|
|
|
|
"url": quote(url),
|
|
|
|
"status": quote(entry["status"]),
|
|
|
|
"name": quote(entry["name"]),
|
|
|
|
"language": quote(entry["language"]),
|
|
|
|
"genre": quote(entry["genre"]),
|
2013-04-09 17:33:50 +00:00
|
|
|
"vote": entry["vote"],
|
2013-03-29 10:01:04 +00:00
|
|
|
}
|
2013-04-09 17:33:50 +00:00
|
|
|
row = u'["<a href=\\"%(url)s\\">%(name)s</a>", "%(genre)s", "%(language)s", "%(status)s", "%(vote)d"]' % args
|
2013-03-29 10:01:04 +00:00
|
|
|
rows.append(row)
|
|
|
|
return u",\n".join(rows)
|
|
|
|
|
|
|
|
|
|
|
|
def write_html(testinfo, outputdir, modified):
|
|
|
|
"""Write index page and all comic pages."""
|
|
|
|
content = get_comicdata(testinfo)
|
|
|
|
date = unicode(strdate(modified))
|
|
|
|
args = {"date": quote(date), "content": content}
|
|
|
|
fname = os.path.join("media", "js", "comicdata.js")
|
|
|
|
with codecs.open(fname, 'w', 'utf-8') as fp:
|
|
|
|
fp.write(comicdata_template % args)
|
|
|
|
comicdir = os.path.join(outputdir, "comics")
|
|
|
|
if not os.path.isdir(comicdir):
|
|
|
|
os.mkdir(comicdir)
|
|
|
|
for key, entry in testinfo.items():
|
|
|
|
write_html_comic(key, entry, comicdir, date)
|
|
|
|
|
|
|
|
|
|
|
|
def write_html_comic(key, entry, outputdir, date):
|
|
|
|
"""Write a comic page."""
|
|
|
|
args = {
|
|
|
|
"url": quote(entry["url"]),
|
2013-04-24 18:25:42 +00:00
|
|
|
"pageurl": quote("%s.html" % key),
|
|
|
|
"editurl": quote("%s_edit.html" % key),
|
2013-03-29 10:01:04 +00:00
|
|
|
"name": quote(entry["name"]),
|
2013-04-24 18:25:42 +00:00
|
|
|
"comic": quote(key),
|
2013-03-29 10:01:04 +00:00
|
|
|
"adult": quote(u"yes" if entry["adult"] else u"no"),
|
2013-04-23 19:51:22 +00:00
|
|
|
"adultchecked": 'checked="checked"' if entry["adult"] else '',
|
2013-03-29 10:01:04 +00:00
|
|
|
"genre": quote(entry["genre"]),
|
|
|
|
"language": quote(entry["language"]),
|
|
|
|
"description": quote(entry["description"]),
|
|
|
|
"status": quote(entry["status"]),
|
|
|
|
"date": quote(date),
|
2013-04-09 17:33:50 +00:00
|
|
|
"vote": entry["vote"],
|
2013-12-05 19:45:13 +00:00
|
|
|
"votename": key,
|
2013-03-29 10:01:04 +00:00
|
|
|
}
|
|
|
|
fname = os.path.join(outputdir, key+".md")
|
|
|
|
with codecs.open(fname, 'w', 'utf-8') as fp:
|
|
|
|
fp.write(comic_template % args)
|
2013-04-23 19:51:22 +00:00
|
|
|
fname = os.path.join(outputdir, key+"_edit.md")
|
|
|
|
with codecs.open(fname, 'w', 'utf-8') as fp:
|
|
|
|
fp.write(comic_edit_template % args)
|
2013-03-29 10:01:04 +00:00
|
|
|
|
|
|
|
|
|
|
|
def quote(arg):
|
|
|
|
"""CGI-escape and jinja-escape the argument."""
|
|
|
|
return cgi.escape(arg.replace(u'{', u'').replace(u'}', u''), quote=True)
|
|
|
|
|
|
|
|
|
|
|
|
def main(args):
|
|
|
|
"""Generate HTML output for test result."""
|
|
|
|
filename = args[0]
|
|
|
|
outputdir = args[1]
|
|
|
|
modified = get_mtime(filename)
|
|
|
|
testinfo = get_testinfo(filename, modified)
|
|
|
|
write_html(testinfo, outputdir, modified)
|
|
|
|
return 0
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
sys.exit(main(sys.argv[1:]))
|