/* appjet:version 0.1 */
import('storage');
var APPNAME = 'comic';
var PPRELOAD = 2;
var NPRELOAD = 8;
var COMIC_LIST_COL = 6;
var itemid = '';
var tp = 0;
var tv = 0;
var v = 0;
var n = 0;
var peval = '';
var imgeval = '';
function clearStorableCollection(c) {
c.forEach(function(v) { c.remove(v); });
}
function defaultString(s) {
return s?s:'';
}
function trim(s) {
return s?s.replace(/^\s+|\s+$/g,""):s;
}
function extract(s, prefix, suffix) {
var i = s.indexOf(prefix);
if (i >= 0) { s = s.substring(i + prefix.length); }
else { return ''; }
if (suffix) {
i = s.indexOf(suffix);
if (i >= 0) { s = s.substring(0, i); }
else { return ''; }
}
return s;
}
function readHotList(fullt) {
var result = new Array();
var t = extract(fullt, '<table id="itempic_dl"', '<td align="center" valign="top">');
while (true) {
var itemid = extract(t, 'html/', '.');
if (!itemid) break;
var imgs = extract(t, '<img src="', '"');
var name = extract(t, '<b>', '<');
var vol = extract(t, '漫畫 ', '</td>').match(/^(\d*)/)[1];
t = extract(t, '</table>', '');
result.push({
url:'http://www.2comic.com/view/' + itemid + '-' + vol + '.html',
img:'http://www.2comic.com' + imgs,
name:name,
itemid:itemid,
vol:vol
});
}
return result;
}
function readLatest(fullt) {
var result = new Array();
var t = extract(fullt, '<table id="itemupdate_dl"', '<td align="center" valign="top">');
// The structure is
// <td align="Center" width="20%">
// <table>... image + url </table>
// name + volume
// </td>
while (true) {
t = extract(t, '<td align="Center" width="20%">', '');
var imgs = extract(t, '<img src="', '"');
if (!imgs) break;
var itemid = extract(t, 'html/', '.');
var name = extract(t, '<b>', '<');
var voltext = trim(extract(t, '/>漫畫', '</td>'));
var volres = voltext.match(/(\d*)(.*)$/);
var vol = volres[1];
var volremark = defaultString(volres[2]);
result.push({
url:'http://www.2comic.com/view/' + itemid + '-' + vol + '.html',
img:'http://www.2comic.com' + imgs,
name:name,
itemid:itemid,
vol:vol,
volremark:volremark
});
}
return result;
}
function readCategory(fullt) {
var result = new Array();
t = extract(fullt, '/images/logo.gif', '</table>');
var res = t.match(/<a href="\/html\/\d*">[^<]*<\/a>/mg);
for (var i=0;i<res.length;i++) {
var r2 = res[i].match(/\/(\d*)">([^<]*)</);
result.push({
catid:r2[1],
name:r2[2]
});
}
return result;
}
function get_cronReadCategory() {
cron_readCategory();
}
function cron_readCategory() {
clearStorableCollection(storage.category.data);
var fullt = wget('http://www.2comic.com');
var result = readCategory(fullt);
var now = new Date().getTime();
storage.category = {time:now, data:new StorableCollection()};
for (var i=0;i<result.length;i++) {
var t = wget('http://www.2comic.com/html/' + result[i].catid + '/');
var catitem = result[i];
// hotlist
var hotlist = readHotList(t);
catitem.hotlist = new StorableCollection();
for (var j=0;j<hotlist.length;j++) {
catitem.hotlist.add(hotlist[j]);
}
// latest
var latest = readLatest(t);
catitem.latest = new StorableCollection();
for (var j=0;j<latest.length;j++) {
catitem.latest.add(latest[j]);
}
storage.category.data.add(catitem);
}
}
function get_cronReadHomepage() {
cron_readHomepage();
}
function cron_readHomepage() {
clearStorableCollection(storage.hotlist.data);
var fullt = wget('http://www.2comic.com');
var result = readHotList(fullt);
var now = new Date().getTime();
storage.hotlist = {time:now, data:new StorableCollection()};
for (var i=0;i<result.length;i++) {
storage.hotlist.data.add(result[i]);
}
}
// get volume list in array
function readVolumeList() {
var url = 'http://www.2comic.com/html/' + itemid + '.html';
var t = wget(url);
t = extract(t, '<table id="rp__ctl0_comiclist_dl"', '</table>');
var data = new Array();
//var json = '';
while (true) {
var volurl = extract(t, "cview('", "'");
if (!volurl) break;
var vol = volurl.match(/(\d*)\.html/)[1];
var voltype = extract(t, 'class="', '"');
t = extract(t, 'class="');
var volname = trim(extract(t, '>', '<'));
t = extract(t, '</a>', '');
//data.push({vol:vol,type:voltype,name:volname});
//if (json) json += ',';
//json += "{vol:" + vol + ",type:" + voltype + "',name='" + volname + "'}";
data.push({vol:vol,type:voltype,name:volname});
}
//json = '[' + json + ']';
return data;
}
// get image, use referer to cheat the site
function get_i() {
var url = request.params.u;
var img = wget(url, {},
{headers:{referer:'http://www.2comic.com/'},
complete:true});
if ("If-Modified-Since" in request.headers) {
response.setStatusCode(304);
response.stop(true);
}
page.setMode("plain");
response.setContentType(img.contentType.split(";")[0]);
response.setCacheable(true);
response.setHeader("Last-Modified", new Date());
page.render();
appjet._native.writeBytes(img.data);
}
// read a page
function get_r() {
var url = request.params.u;
if (!url) {
var param_i = request.params.i;
if (!param_i) {
return;
}
var param_v = request.params.v;
if (!param_v) {
param_v = 1;
}
url = 'http://www.2comic.com/view/' + param_i + '-' + param_v + '.html';
}
var t = '';
var error = '';
try {
t = wget(url);
}
catch (ex) {
get_main('找不到此頁,請從新再試');
return;
}
var n = url.match(/\?n=(\d*)/);
if (n) {
n = parseInt(n[1], 10);
}
else {
n = 1;
}
itemid = t.match(/var itemid="(\d*)";/);
if (!itemid) {
get_main('找不到此頁,請從新再試');
return;
}
itemid = itemid[1];
tp = t.match(/var tp=parseInt\("(\d*)"\);/);
tp = parseInt(tp[1], 10);
tv = t.match(/var tv=parseInt\("(\d*)"\)/);
tv = parseInt(tv[1], 10);
v = t.match(/var v=parseInt\("(\d*)"\);/);
v = parseInt(v[1], 10);
peval = t.match(/p\+="_"[^;]*;/)[0];
imgeval = t.match(/document\.getElementById\("TheImg"\)\.src=("[^;]*;)/)[1];
var title = t.match(/<title>([^<]*)<\/title>/);
title = title?title[1]:'';
title = title.replace(' - 2Comic.com', '');
title = 'comic - ' + title;
var vollist = readVolumeList();
// output the HTML
page.setMode("plain");
print(raw("""
<html>
<head>
<title>""" + title + """</title>
<style>
body { font-family: Arial; }
#img-curr { cursor:pointer; }
#navbar, #navbar select { font-size:20pt; }
#navbar select { vertical-align:top; }
#navbar a, a:visited { color:blue; text-decoration:none; }
#loading-layer {
font-weight:bold;
background-color:#ffc;
color:#f33;
z-index:10000;
position:fixed;
border:1px gray solid;
padding:5px 10px;
left:0px;
top:0px;
-moz-border-radius: 0 0 10px 0;
}
</style>
<!--[if lt IE 7]>
<script src="http://ie7-js.googlecode.com/svn/version/2.0(beta3)/IE7.js" type="text/javascript"></script>
<![endif]-->
<script language='javascript'>
var curr = 1;
var itemid = """ + itemid + """;
var totalpage = """ + tp + """;
var vol = """ + tv + """;
var title = '""" + title + """';
var PPRELOAD = """ + PPRELOAD + """;
var NPRELOAD = """ + NPRELOAD + """;
var lastLoadingTime = 0;
function getWindowSize() {
var myWidth = 0, myHeight = 0;
if( typeof( window.innerWidth ) == 'number' ) {
//Non-IE
myWidth = window.innerWidth;
myHeight = window.innerHeight;
} else if( document.documentElement && (
document.documentElement.clientWidth ||
document.documentElement.clientHeight ) ) {
//IE 6+ in 'standards compliant mode'
myWidth = document.documentElement.clientWidth;
myHeight = document.documentElement.clientHeight;
} else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
//IE 4 compatible
myWidth = document.body.clientWidth;
myHeight = document.body.clientHeight;
}
return {width:myWidth,height:myHeight};
}
function getImgUrl(n) {
if (n<1) return 'about:blank';
if (n>totalpage) return 'about:blank';
var p = "";
if (n<10) p = "00" + n;
else if (n<100) p = "0" + n;
else p = n;
var m = (parseInt((n-1)/10)%10)+(((n-1)%10)*3);
""" + " " + peval + "\n imgurl = " + imgeval + """
return "http://""" + APPNAME + """.appjet.net/i?u=" + encodeURIComponent(imgurl);
//return
"http://quickthumbnail.com/func_resizer.php?width=600&filename=" +
encodeURIComponent("http://m2comic.appjet.net/i?u=" +
encodeURIComponent(imgurl));
}
function init() {
var res = document.location.href.match(/#(\d*)$/);
if (res) {
curr = parseInt(res[1], 10);
}
changepage();
if (document.addEventListener) {
document.addEventListener('keydown', keyHandler, false);
}
else if (document.attachEvent) {
document.attachEvent('onkeydown', keyHandler);
}
else {
document['onkeydown'] = keyHandler;
}
window.setInterval(checkLoading, 500);
}
function keyHandler(e) {
var code;
e = e || window.event;
if (e.keyCode) {
code = e.keyCode;
}
else if (e.which) {
code = e.which;
}
else {
return;
}
// checking for modifiers lets us ignore those
if (e.altKey || e.ctrlKey || e.metaKey) {
return false;
}
// We also don't want to interfere with regular user typing
if (e.target && e.target.nodeName) {
var targetNodeName = e.target.nodeName.toLowerCase();
if (targetNodeName == "textarea" ||
(targetNodeName == "input" && e.target.type &&
e.target.type.toLowerCase() == "text")) {
return false;
}
}
if (code == 78) {
// n
next();
return true;
}
else if (code == 66) {
// b
prev();
return true;
}
return false;
}
function moveImageToCurrent(from) {
var currimg = document.getElementById('img-curr');
var size = 0;
var fromsize = from?from.width:currimg.width;
var bestsize = getWindowSize().width - 30;
if (fromsize && fromsize > bestsize) {
size = bestsize;
}
if (size > 0) {
currimg.width = size;
}
else {
currimg.removeAttribute('width');
}
if (from) currimg.src = from.src;
}
function updatePageInfo() {
document.title = title + ' - ' + curr + '/' + totalpage;
document.getElementById('currpage-select').selectedIndex = curr - 1;
document.location.href = document.location.href.replace(/#\d*$/, '') + '#' + curr;
window.scroll(0, 0);
}
function checkLoading() {
var loading = lastLoadingTime && (new Date().getTime() - lastLoadingTime > 1000);
if (loading) {
document.getElementById('loading-layer').style.display = '';
}
else {
document.getElementById('loading-layer').style.display = 'none';
}
}
function setupCheckLoading(func) {
if (!lastLoadingTime) lastLoadingTime = new Date().getTime();
document.getElementById('img-curr').onload = function() {
lastLoadingTime = 0;
checkLoading();
if (func) func.call();
}
}
function prev() {
if (curr <= 1) {
alert('你已經在第一頁');
return;
}
var tmp = document.getElementById('img-curr').src;
document.getElementById('img-curr').src = document.getElementById('img-p1').src;
setupCheckLoading();
for (var i=NPRELOAD;i>1;i--) {
document.getElementById('img-n' + i).src = document.getElementById('img-n' + (i-1)).src;
}
document.getElementById('img-n1').src = tmp;
for (var i=1;i<PPRELOAD;i++) {
document.getElementById('img-p' + i).src = document.getElementById('img-p' + (i+1)).src;
}
document.getElementById('img-p' + PPRELOAD).src = getImgUrl(curr - PPRELOAD - 1);
curr--;
updatePageInfo();
}
function next() {
if (curr >= totalpage) {
alert('你已經在最後一頁');
return;
}
var tmp = document.getElementById('img-curr').src;
moveImageToCurrent(document.getElementById('img-n1'));
//document.getElementById('img-curr').src = document.getElementById('img-n1').src;
setupCheckLoading();
for (var i=PPRELOAD;i>1;i--) {
document.getElementById('img-p' + i).src = document.getElementById('img-p' + (i-1)).src;
}
document.getElementById('img-p1').src = tmp;
for (var i=1;i<NPRELOAD;i++) {
document.getElementById('img-n' + i).src = document.getElementById('img-n' + (i+1)).src;
}
document.getElementById('img-n' + NPRELOAD).src = getImgUrl(curr + NPRELOAD + 1);
curr++;
updatePageInfo();
}
function changepage() {
document.getElementById('img-curr').src = getImgUrl(curr);
setupCheckLoading(function() {
// load the current page first
moveImageToCurrent(null);
updatePageInfo();
for (var i=1;i<=PPRELOAD;i++) {
document.getElementById('img-p' + i).src = getImgUrl(curr - i);
}
for (var i=1;i<=NPRELOAD;i++) {
document.getElementById('img-n' + i).src = getImgUrl(curr + i);
}
});
/*
document.getElementById('img-curr').onload = function() {
updatePageInfo();
for (var i=1;i<=PPRELOAD;i++) {
document.getElementById('img-p' + i).src = getImgUrl(curr - i);
}
for (var i=1;i<=NPRELOAD;i++) {
document.getElementById('img-n' + i).src = getImgUrl(curr + i);
}
}
*/
}
function onSelectChangePage() {
curr = document.getElementById('currpage-select').selectedIndex + 1;
changepage();
}
function onSelectChangeVol() {
var sel = document.getElementById('currvol-select');
document.location.assign('/r?i=' + itemid + '&v=' + (sel.options[sel.selectedIndex].value));
}
</script>
"""));
print(raw("""
</head>
<body onload='init()'>
<img id='img-curr' border='0' onclick='javascript:next()'/>
"""));
for (var i=1;i<=PPRELOAD;i++) {
print(raw("<img id='img-p" + i + "' src='about:blank;' style='display:none;''/>\n"));
}
for (var i=1;i<=NPRELOAD;i++) {
print(raw("<img id='img-n" + i + "' src='about:blank;' style='display:none;''/>\n"));
}
print(raw("""
<div id='navbar'>
<a href='javascript:void(0)' onclick='javascript:prev()' style='margin-right:20px;'>前一頁</a>
<select id='currpage-select' onchange='onSelectChangePage()' style='margin-right:20px;'>
"""));
// page list
for (var i=1;i<=tp;i++) {
print(raw("<option value='" + i + "'>" + i + "/" + tp + "</option>\n"));
}
print(raw("""
</select>
<a href='javascript:void(0)' onclick='javascript:next()' style='margin-right:20px;'>後一頁</a>
其他期數:
<select id='currvol-select' onchange='onSelectChangeVol()' style='margin-right:20px;'>
"""));
// volume list
for (var i=0;i<vollist.length;i++) {
print(raw("<option value='" + vollist[i].vol + "'" + (vollist[i].vol==tv?" selected='selected'":"") + ">" + vollist[i].name + "</option>\n"));
}
print(raw("""
</select>
<a href='/'>回到目錄</a>
</div>
<div id='loading-layer' style='display:none;'>
<img src='http://appjet.com/img/status-ball.gif' style='vertical-align:middle;'/>
Loading
</div>
</body>
</html>
"""));
}
function getComicListHTML(data) {
//var TD_WIDTH = parseInt(100/COMIC_LIST_COL, 10) + '%';
var TD_WIDTH = '120px';
var latestData = new Array();
data.forEach(function(v) {
latestData.push(v);
});
var html = "<table class='comiclist' border='0' cellspacing='1' cellpadding='2'>";
var idx = 0;
while (idx < latestData.length) {
html += "<tr>";
for (var j=0;j<COMIC_LIST_COL;j++) {
if (idx < latestData.length) {
var item = latestData[idx];
var url = "/r?i=" + item.itemid + "&v=" + item.vol;
html += "<td width='" + TD_WIDTH + "'><a href='" + url + "'><img src='" + item.img + "' style='margin-bottom:10px' border='0'/></a><br/>" + item.name + "<br/><a href='" + url + "'>" + item.vol + "</a></td>";
idx++;
}
else {
html += "<td></td>";
}
}
html += "</tr>";
}
html += "</table>";
return html;
}
function printHeading(title) {
print(raw("""
<html>
<head>
<title>comic""" + (title?(" - " + title + " "):"") + """</title>
<style>
body { line-height: 1.5em; }
body, td { font-family: Arial; }
table.comiclist { background-color:#aaa; }
table.comiclist td { text-align:center; vertical-align:top; background-color:white; }
</style>
</head>
<body>
<h1><a
href='/'><img src='http://www.2comic.com/images/logo.gif'
style='vertical-align:middle;' border='0'/></a>
2Comic 動漫易精簡版</h1>
"""));
}
function printFooter() {
print(raw("<h3>分類</h3>"));
var html = '';
storage.category.data.forEach(function(v) {
html += (html?' | ':'') + "<a href='/c?c=" + v.catid + "'>" + v.name + "</a>";
});
print(raw(html));
printRecommend();
print(raw("""
<br/>
<form action='/r' method='get'>
貼上 2Comic 動漫易的漫畫網址:<br/>
<input type='text' size='40' name='u' />
<input type='submit' value='觀看'/>
<br/>
<a href='http://www.2comic.com/all.html' target='_blank'>請參閱 2Comic 動漫易的完整動漫列表</a>
</form>
</body>
</html>
"""));
}
function printRecommend() {
var TITLE = [
{name: '課長島耕作', itemid:1620, vol:17},
{name: '部長島耕作', itemid:526, vol:13},
{name: '董事島耕作', itemid:1018, vol:8},
{name: '青年島耕作', itemid:5149, vol:3},
{name: '欺詐游戲', itemid:1688, vol:59}
];
print(raw("<h3>網主推介</h3>"));
for (var i=0;i<TITLE.length;i++) {
var html = TITLE[i].name + '<br/>';
for (var j=1;j<=TITLE[i].vol;j++) {
html += (j>1?' | ':'') + "<a href='/r?i=" +
TITLE[i].itemid + "&v=" + j +
"'>" + j + "</a>";
}
print(raw(html + "<br/>"));
}
}
// read a category
function get_c() {
var c = request.params.c;
if (!c) c = 1;
var cat = null;
storage.category.data.filter({catid:c}).forEach(function(v) {
cat = v;
return false;
});
var title = cat?cat.name:'';
page.setMode("plain");
printHeading(title);
if (cat) {
print(raw("<h3>" + title + "熱門連載</h3>"));
print(raw(getComicListHTML(cat.hotlist)));
print(raw("<h3>" + title + "最近更新</h3>"));
print(raw(getComicListHTML(cat.latest)));
}
printFooter();
}
function get_main(error) {
page.setMode("plain");
printHeading();
if (error) {
print(raw("<h1>" + error + "</h1>"));
}
print(raw("<h3>最新熱門連載</h3>"));
print(raw(getComicListHTML(storage.hotlist.data)));
printFooter();
}
function get_dummy() {}
function get_test() {
page.setMode("plain");
print(raw("""
<html>
<head>
<title>m2comic</title>
<script>
function alertSize() {
var myWidth = 0, myHeight = 0;
if( typeof( window.innerWidth ) == 'number' ) {
//Non-IE
myWidth = window.innerWidth;
myHeight = window.innerHeight;
} else if( document.documentElement && (
document.documentElement.clientWidth ||
document.documentElement.clientHeight ) ) {
//IE 6+ in 'standards compliant mode'
myWidth = document.documentElement.clientWidth;
myHeight = document.documentElement.clientHeight;
} else if( document.body && ( document.body.clientWidth || document.body.clientHeight ) ) {
//IE 4 compatible
myWidth = document.body.clientWidth;
myHeight = document.body.clientHeight;
}
return {width:myWidth,height:myHeight};
}
function init() {
alertSize();
}
</script>
</head>
<body onload='init()'>
</body>
</html>
"""));
}
dispatch();