Light12306/RwTicketAssistantV2/app/background.js
2014-09-13 03:44:02 +08:00

1585 lines
42 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

var MANIFEST = chrome.runtime.getManifest();
var INFOBAR = chrome.infobars || (chrome.experimental && chrome.experimental.infobars);
var isDebug = (compressFunc + '').indexOf("false") != -1;
var bv = window.external.LiebaoGetVersion && window.external.LiebaoGetVersion() || /Chrome\/([\d\.]+)/i.exec(navigator.userAgent)[1];
var entry12306 = false;
var log = (function () {
var fun = function () {
this.print = function () {
/// <summary>向控制台打印消息</summary>
if (!isDebug) return;
console.log.apply(console, $.makeArray(arguments));
};
return this;
};
return new fun();
})();
function compressFunc() {
return false;
}
var notification = (function () {
var notify = function () {
var __ = this;
var notifyMap = {};
this.mapParam = function (opts) {
return {
type: opts.type || "basic",
title: opts.title || "提示",
message: opts.message || "",
iconUrl: opts.iconUrl || "/icons/icon_n.png",
//contextMessage: opts.contextMessage || "",
priority: opts.priority || 0,
eventTime: opts.eventTime || null,
buttons: _.map(opts.buttons, function (e) {
return { title: e.title, iconUrl: e.iconUrl || "/icons/icon_16.png" };
}) || null,
imageUrl: opts.imageUrl || null,
items: _.map(opts.items, function (e) {
return { title: e.title, message: e.message };
}) || null//,
//progress: opts.progress || null,
//isClickable: opts.isClickable || true
};
};
__.create = function (opts) {
var opt = __.mapParam(opts);
var id = opts.id || "";
chrome.notifications.create(id, opt, function (_id) {
notifyMap[_id] = opts;
opts.id = _id;
});
opts.update = function () {
__.update(opts);
};
opts.clear = function () {
__.clear(opts.id);
};
};
__.update = function (opts) {
var opt = __.mapParam(opts);
chrome.notifications.update(opts.id, opt, function () {
opts.onUpdate && opts.onUpdate.apply(opts, $.makeArray(arguments));
});
};
__.clear = function (id) {
chrome.notifications.clear(id, function () {
opts.onClear && opts.onClear.apply(opts, $.makeArray(arguments));
});
};
__.getAll = function (callback) {
chrome.notifications.getAll(callback);
};
__.getPermissionLevel = function (callback) {
chrome.notifications.getPermissionLevel(callback);
};
chrome.notifications.onClicked.addListener(function (id) {
var opts = notifyMap[id];
if (opts === undefined || opts === null) return;
if ($.isFunction(opts.onClick)) {
opts.onClick.apply(this);
}
});
chrome.notifications.onClosed.addListener(function (id, byUser) {
var opts = notifyMap[id];
if (opts === undefined || opts === null) return;
if ($.isFunction(opts.onClose)) {
opts.onClose.apply(this, [byUser]);
}
});
chrome.notifications.onButtonClicked.addListener(function (id, index) {
var opts = notifyMap[id];
if (opts === undefined || opts === null) return;
var button = opts.buttons && opts.buttons[index];
if (!button || !$.isFunction(button.onClick)) return;
button.onClick.apply(opts);
});
chrome.runtime.onMessage.addListener(function (m, sender) {
if (m.action === "showNotification")
__.create(
{ message: m.detail.message, title: m.detail.title, iconUrl: m.detail.iconUrl }
);
else if (m.action === "notify") __.create(m.detail);
else if (m.action === "attention" && sender.tab) {
chrome.tabs.update((m.detail && m.detail.tabid) || sender.tab.id, { active: true, highlighted: true });
chrome.windows.update((m.detail && m.detail.windowid), { drawAttention: true, focused: true, state: "maximized" });
}
});
};
return new notify();
})();
(function () {
var notifyId;
var tabid, message;
//未加载提醒
var closeCallback = function (id) {
if (id === notifyId) {
notifyId = null;
}
};
var clickCallback = function (id, idx) {
if (id === notifyId && idx === 0) {
chrome.tabs.update(tabid, {
url: chrome.extension.getURL(message.detail.url.indexOf("/otn") != -1 ? "/infobar/main.html?new" : "/infobar/main.html"),
selected: true
}, function () { });
chrome.notifications.clear("notLoadMessage", function () { });
}
};
chrome.notifications.onClosed.addListener(closeCallback);
chrome.notifications.onButtonClicked.addListener(clickCallback);
chrome.runtime.onMessage.addListener(function (m, sender, response) {
if (m.action && m.action === "notLoadTip") {
message = m;
tabid = sender.tab.id;
if (notifyId) {
chrome.notifications.update(notifyId, {
type: 'basic',
iconUrl: '/icons/icon_n.png',
title: '订票助手未启动',
message: '订票助手未加载,请点击工具栏『订票助手』图标并点击订票菜单来使用。',
buttons: [
{ title: '或点击这里启动订票助手', iconUrl: "/infobar/theme/plus_16.png" }
]
}, function () {
});
} else {
chrome.notifications.create('', {
type: 'basic',
iconUrl: '/icons/icon_n.png',
title: '订票助手未启动',
message: '订票助手未加载,请点击工具栏『订票助手』图标并点击订票菜单来使用。',
buttons: [
{ title: '或点击这里启动订票助手', iconUrl: "/infobar/theme/plus_16.png" }
]
}, function (id) {
notifyId = id;
});
}
setTimeout(function () {
closeCallback(notifyId);
}, 5000);
}
});
})();
//#region 系统配置处理
var CFG_MANGER = (function () {
function manager() {
var __ = this;
var loaded = false;
var lastUpdate = null;
var sleepTime = 1000 * 1200;
var timerId = null;
this.baseConfig = {
appendCacheTagHeader: true,
showRealSeatCount: true,
autoSubmitAfterVerifyCode: true,
autoLoginAfterVerifyCode: true,
rememberLoginUser: true,
rememberLoginPwd: true,
enableSoundPrompt: true,
enablePopupPrompt: true,
musicUrl: "http://static.liebao.cn/resources/audio/music2.ogg",
submitOrderDelay: 5,
refreshDelay: 5,
autoWaitToSell: true,
keepOnline: true,
blockDynamicJs: false,
enableRealTimeTicketQuery: true,
showTicketPrice: true,
otnAutoConfirmOrderDelay: 0,
dynamicAutoConfirmOrderDelay: 1000,
dynamicAutoSubmitOrderDelay: 5000,
otnAutoSubmitOrderDelay: 0,
enableSelfTrack: true,
enableServerAutoChange: true,
enableAutoCaptcha: true && typeof window.external.LieBaoSign === 'function',
autoCaptchaFailedLimit: 5,
captchaServerUrl: "http://api.12306.liebao.cn/code.php",
appendPriceUnit: true,
blockVcVerify: false,
blockQueueCount: false,
chatServerApi: "http://12306.liebao.cn/index.php?r=Api/GetChatRoom"
};
this.sysConfig = {};
this.userConfig = { enableAutoCaptcha: false };
if (localStorage["sysConfig"])
this.sysConfig = $.extend(this.sysConfig, JSON.parse(localStorage["sysConfig"]));
if (localStorage["userConfig"])
this.userConfig = JSON.parse(localStorage["userConfig"]);
this.refresh = function () {
__.config = $.extend({}, __.baseConfig, __.userConfig, __.sysConfig);
};
this.refresh();
//定时刷新请求
this.refresh = function () {
if (timerId) {
clearTimeout(timerId);
timerId = null;
}
if (entry12306 || !loaded) {
lastUpdate = new Date();
$.getJSON("http://storage.fishlee.net/soft/files/44/rwticketconfig.json?" + Math.random(), function (data) {
if (typeof (data.enableAutoCaptcha) === 'undefined' || data.enableAutoCaptcha)
data.enableAutoCaptcha = data.enableAutoCaptcha && typeof window.external.LieBaoSign === 'function';
localStorage["sysConfig"] = JSON.stringify(data);
__.sysConfig = data;
__.config = $.extend({}, __.baseConfig, __.userConfig, __.sysConfig);
chrome.runtime.sendMessage({ action: "sysConfigUpdate", detail: __.config });
});
}
var m = new Date().getMinutes();
if (m >= 50 || m <= 15) {
timerId = setTimeout(__.refresh, 10 * 60 * 1000);
} else {
timerId = setTimeout(__.refresh, sleepTime);
}
};
this.isEnabled = function (tag) {
};
var msgHandler = function (m, s, r) {
if (m && m.action === 'enter12306') {
sleepTime = 20 * 60 * 1000;
if (lastUpdate === null || (new Date() - lastUpdate) >= 20 * 60 * 1000)
__.refresh();
}
if (m && m.action === 'setUserConfig') {
__.userConfig = $.extend({}, __.userConfig, m.detail);
__.config = $.extend({}, __.baseConfig, __.userConfig, __.sysConfig);
localStorage["userConfig"] = JSON.stringify(__.userConfig);
chrome.runtime.sendMessage({ action: "sysConfigUpdate", detail: __.config });
}
};
chrome.runtime.onMessage.addListener(msgHandler);
chrome.runtime.onMessageExternal.addListener(msgHandler);
this.refresh();
loaded = true;
return this;
};
var mm = new manager();
var mmCallback = function (m, s, r) {
if (m.action === "getSysConfig") {
r({ action: "responseSysConfig", detail: mm.config });
}
if (m.action === "getBaseSysConfig") {
r({ action: "responseBaseSysConfig", detail: $.extend(mm.baseConfig, mm.sysConfig) });
}
};
chrome.runtime.onMessage.addListener(mmCallback);
chrome.runtime.onMessageExternal.addListener(mmCallback);
return mm;
})();
//#endregion
//#region 检测更新和更新通知
//TODO 检测更新
(function showNotificationIfUpdated() {
if (window.localStorage["cv"] != MANIFEST.version) {
window.localStorage["cv"] = MANIFEST.version;
notification.create({
title: "更新成功",
message: "您的订票助手已成功更新至 " + MANIFEST.version + " :-)"
});
}
})();
//#endregion
//#region 运行环境检测,以及自动处理启动
(function checkRunModeAndBootStrap() {
localStorage["inforbarMode"] = INFOBAR ? "1" : "0";
if (!INFOBAR) return;
chrome.runtime.onMessage.addListener(function (msg, sender, resp) {
if (msg.action && msg.action == "isInforbarEnabled") {
resp(INFOBAR ? true : false);
}
});
function checkIfInfobarShown(tabid) {
var views = chrome.extension.getViews({ type: "infobar" });
for (var i in views) {
var v = views[i];
if (v.location.search == "?" + tabid) {
return true;
}
}
return false;
}
var showInfobar = function (tabid, page, isOtn) {
//if (checkIfInfobarShown(tabid)) {
// INFOBAR.show({
// tabId: tabid,
// height: 155
// });
// return;
//}
//显示infobar
INFOBAR.show({
tabId: tabid,
height: 155,
path: "/infobar/" + page + ".html?" + (isOtn ? "new" : "old") + tabid
});
};
chrome.tabs.onUpdated.addListener(function (tabid, changeinfo, tab) {
if (changeinfo.status == "complete") {
if (/https?:\/\/(www|dynamic|kyfw)\.12306\.cn\/otn.*/i.test(tab.url)) {
showInfobar(tab.id, "main", true);
}
}
});
//初始化infobar
/*chrome.tabs.query({ url: "*://kyfw.12306.cn/*" }, function (ta) {
$.each(ta, function () {
if (!checkIfInfobarShown(this.id)) {
showInfobar(this.id, true);
}
});
});*/
})();
//#endregion
//#region 对请求的处理
(function requestManager() {
var filter = {
urls: ["*://*.12306.cn/*"],
types: ["main_frame", "sub_frame", "stylesheet", "script", "image", "object", "xmlhttprequest", "other"]
};
var extraInfo = ["blocking", "requestHeaders"];
var autoEnableTrainClassRandom = function (url) {
var qtc = /trainClass=([^&]+)&/g.exec(url)[1];
var tc = qtc.replace(/%23/g, "#").split('#');
if (tc[0] == 'QB') return null;
//QB#D#Z#T#K#QT#
var flags = [0, 0, 0, 0, 0];
for (var t in tc) {
var code = tc[t];
if (code == 'D') flags[0] = 1;
else if (code == 'Z') flags[1] = 1;
else if (code == 'T') flags[2] = 1;
else if (code == 'K') flags[3] = 1;
else if (code == 'QT') flags[4] = 1;
}
//随机化各个请求
var result = [];
var order = ["D", "Z", "T", "K", "QT"];
for (var i = 0; i < flags.length; i++) {
if (!flags[i])
flags[i] = Math.random() > 0.5 ? 1 : 0;
if (flags[i])
result.push(order[i]);
}
//合并请求
var ntc = result.join("#") + "#";
return url.replace(qtc, escape(ntc));
};
function processRequest(details) {
var url = details.url;
var skipBlacklist = !CFG_MANGER.config.blockDynamicJs;
var newHeaders = {};
for (var i = 0; i < details.requestHeaders.length; ++i) {
var h = details.requestHeaders[i];
var name = h.name;
var value = h.value;
if (name === 'User-Agent') {
newHeaders[name] = "Mozilla/5.0 (MSIE 9.0; Windows NT 6.1; Trident/5.0;)";
} else if (h.name == "TRefer") {
newHeaders["Referer"] = value;
} else if (h.name == "Referer") {
if (!newHeaders["Referer"] && value.indexOf("12306.cn") != -1)
newHeaders["Referer"] = value;
} else if (name.indexOf("Fish-") != -1) {
name = name.substr(5);
if (!value) {
if (newHeaders[name])
delete newHeaders[name];
} else {
newHeaders[name] = value;
}
skipBlacklist = true;
} else if (!newHeaders[name]) {
newHeaders[name] = value;
}
}
var headerCollection = [];
for (var i in newHeaders) {
headerCollection.push({ name: i, value: newHeaders[i] });
}
if (!skipBlacklist && $.isFunction(window.cbl)) {
//检测是否在黑名单中
if (window.cbl.call(details, url, newHeaders)) {
return { cancel: true };
}
}
if (CFG_MANGER.config.appendCacheTagHeader && url.indexOf("querySingleAction.do?method=queryLeftTicket") != -1) {
headerCollection.push({ name: "If-None-Match", value: Math.random() + "" });
headerCollection.push({ name: "Pragma", value: "No-cache" });
// return { requestHeaders: headerCollection, redirectUrl: autoEnableTrainClassRandom(details.url) };
}
return { requestHeaders: headerCollection };
}
chrome.webRequest.onBeforeSendHeaders.addListener(processRequest, filter, extraInfo);
chrome.webRequest.onBeforeRequest.addListener(function (data) {
//if (data.url.indexOf("querySingleAction.do?method=queryLeftTicket") != -1) {
// return { redirectUrl: autoEnableTrainClassRandom(data.url) };
//}
//if (data.url.indexOf("indexAction.do") != -1 || /Action\.do\?method=[a-z\d]{1,3}$/i.test(data.url)) {
// return { cancel: true };
//}
return null;
}, filter, ["blocking"]);
})();
//#endregion
//#region 检测、拦截
(function () {
window.chrome.extension.onRequest.addListener(function (request, sender, sendResponse) {
var fn = request.action;
if (fn == "notify") {
notification.create({
title: request.title || '订票助手',
message: request.message
});
}
if (fn == "ajax") {
var opt = request.opt;
opt.headers = opt.headers || {
};
var headerNew = {};
for (var i in opt.headers) {
headerNew["Fish-" + i] = opt.headers[i];
}
opt.headers = headerNew;
opt.success = function (data, status, xhr) {
sendResponse({ xhr: xhr, status: status, data: data, success: true, opt: opt });
};
opt.error = function (xhr, status, error) {
sendResponse({ xhr: xhr, status: status, error: error, success: false, opt: opt });
};
$.ajax(opt);
return true;
}
if (fn == "getRules") {
sendResponse(window.rules.data);
return;
}
if (fn == "refreshRule") {
window.refreshRule();
return;
}
});
});
window.cbl = function (u, h) {
for (var i in window.rules.block) {
if (window.rules.block[i].test(u)) return true;
}
return false;
};
(function () {
var lastChecked = null;
var url = "http://store.fishlee.net/files/44/rule.json?" + Math.random();
var checkRule = function () {
if (lastChecked && (new Date() - lastChecked) / 1000 / 60 < 10) return;
$.get(url, function (data) {
try {
window.rules = JSON.parse(data);
cache(data);
processRule();
} catch (e) {
}
lastChecked = new Date();
setTimeout(checkRule, 20 * 60 * 1000);
}, "text");
};
var cache = function (data) {
localStorage.cn12306rule = data;
};
var load = function () {
if (localStorage.cn12306rule) {
window.rules = JSON.parse(localStorage.cn12306rule);
} else {
window.rules = { "block": ['JsAction\\.do'], data: 'window.cbl=function(n){return!1|/JsAction\\.do/i.test(n)};window.rc=function(n,t){var i,r,u;return/JsAction\\.do/i.test(n)?(i=/value\\.indexOf\\(\'([01])\'\\)/i.exec(t)&&RegExp.$1||\"0\",i=i==\"0\"?\"1\":\"0\",i=i.padRight(4,i),r=\"\",u=\"key\",t=t.replace(/(var\\s*)([a-z\\d_]+)\\s*=\\s*[\'\"]([a-z\\d=]+)[\'\"]/gi,function(n,t,f,e){return r=e,u=f,\'return \"\'+r+\":\"+i+\'\";\'}),t=t.replace(/window\\..*?Version/gi,\"undefined\"),t=t.replace(/(var\\s*([a-z]+)chek)/gi,\"return \"+u+\'+\":\'+i+\'\"; $1\'),t=t.replace(/(return\\s*key[^;]+)/gi,\"return \"+u+\'+\":\'+i+\'\";\'),t=t.replace(/=\\s*gc\\(\\s*\\)/gi,\'=\"\'+r+\":\"+i+\'\"\'),t.replace(/(arr)=\\[[\\w\\W]+?\\]\\s*;/gi,\"$1=[];\")):t};window.dynamicLoad=function(n){$.each([\"script[src*=\'JsAction.do\']\"],n)}' };
}
processRule();
checkRule();
};
var processRule = function () {
var regList = [];
$.each(window.rules.block, function () {
regList.push(new RegExp(this + '', "gi"));
});
window.rules.block = regList;
};
window.refreshRule = function () {
checkRule();
};
if (CFG_MANGER.config.blockDynamicJs)
load();
chrome.runtime.onMessage.addListener(function (m, s, r) {
if (m && m.action === 'sysConfigUpdate') {
if (CFG_MANGER.config.blockDynamicJs)
load();
}
});
})();
//#endregion
//#region 服务器测速
(function () {
/// <summary>服务器IP</summary>
var valid = window.external.LieBaoLookupDnsAddress ? 1 : 0;
chrome.runtime.onMessage.addListener(function (m, s, r) {
if (m && m.action === "servervalid")
r({ valid: valid });
});
chrome.runtime.onMessageExternal.addListener(function (m, s, r) {
if (m && m.action === "servervalid")
r({ valid: valid });
});
if (!valid)
return;
var serviceUrl = "http://www.fishlee.net/apps/cn12306/ipservice/getlist";
var reportUrl = "http://www.fishlee.net/apps/cn12306/ipservice/update2";
var inupdateMode = false;
var serverStorage = {
count: 0,
valid: 0,
timeout: 0,
failed: 0,
lastUpdate: null,
validList: [],
status: 0
};
var serverlist = [],
testedServer = [],
currentServer = {
"kyfw.12306.cn": { ip: null, speed: null }
//, "dynamic.12306.cn": { ip: null, speed: null }
//, "www.12306.cn": { ip: null, speed: null }
};
var servers = [
//{ host: "dynamic.12306.cn", url: "http://dynamic.12306.cn/otn/", count: 0 },
//{ host: "www.12306.cn", url: "http://www.12306.cn/otn/", count: 0 },
{ host: "kyfw.12306.cn", url: "https://kyfw.12306.cn/otn/", count: 0 }
],
serverIndex = 0;
var localDns = {}, initialChange = false;
//消息
(function () {
var messageCallback = function (message, sender, response) {
if (message && message.action) {
if (message.action === "getServerStatus") {
response(serverStorage);
} else if (message.action === "getServerList") {
response(serverStorage.status == 2 ? _.flatten([testedServer, serverlist]) : []);
} else if (message.action === "getCurrentServer") {
response(currentServer);
}
}
};
chrome.runtime.onMessage.addListener(messageCallback);
chrome.runtime.onMessageExternal.addListener(messageCallback);
})();
var randomTake = function (list, count) {
if (!list || list.length <= count) return list;
var result = [];
var randomIndex;
while (result.length < count) {
randomIndex = Math.floor(Math.random() * list.length);
result.push(list.splice(randomIndex, 1));
}
return result;
};
var loadFromServer = function () {
serverStorage.status = 1;
chrome.runtime.sendMessage({ action: "serverStateChange", detail: { state: serverStorage.status } });
chrome.runtime.sendMessage({ action: "track", detail: { type: 90 } });
$.getJSON(serviceUrl).done(function (data) {
//取100个
data = _.groupBy(data, function (e) { return e.host; });
for (var host in data) {
data[host] = randomTake(data[host], 100);
}
data = _.flatten(data);
serverlist = data;
serverStorage.count = data.length;
serverStorage.valid = serverStorage.timeout = serverStorage.failed = 0;
//增加本地解析的地址
if (localDns) {
_.each(localDns, function (ips, host) {
_.each(ips, function (ip) {
serverlist.push({ host: host, ip: ip });
});
});
}
runServerTest();
}).fail(function () {
setTimeout(loadFromServer, 1000 * 60 * 10);
});
};
var runServerTest = function () {
testedServer = [];
serverStorage.status = 2;
chrome.runtime.sendMessage({ action: "serverStateChange", detail: { state: serverStorage.status } });
serverTestEntry();
};
var serverTestEntry = function () {
if (serverlist.length) {
testServer(serverlist.splice(0, 1), serverTestEntry);
} else {
filterServer();
}
};
var ajaxWrapper = function (url, host) {
var def = new $.Deferred();
chrome.tabs.httpRequest(url, "User-Agent: MSIE 9.0\r\nHost: " + host, 3000, function (result) {
var resp = null;
try {
resp = JSON.parse(result);
} catch (e) {
}
if (!resp) {
def.reject(0, 'unknown error.');
return;
}
var a = resp[0];
var b = resp[1];
var c = resp[2];
if (!a) {
if (b === 10001) {
//timeout
def.reject(0, 'timeout');
} else {
def.reject(b, c);
}
} else {
def.resolve(c, b);
}
});
return def.promise();
};
var testServer = function (server, callback) {
server = server[0];
server.host = server.host || "kyfw.12306.cn";
var url = "https://" + server.ip + "/otn/";
var time = new Date();
ajaxWrapper(url, server.host).done(function (text) {
if (!text || text.indexOf("客运服务") !== -1)
server.speed = new Date() - time;
else {
server.speed = -2;
}
}).fail(function () {
server.speed = -1;
}).always(function () {
server.status = server.speed == -1 || server.speed == -2 ? -1 : server.speed > 1000 ? -2 : 1;
if (inupdateMode) {
if (server.status === -1) serverStorage.failed++;
else if (server.status === -2) serverStorage.timeout++;
else if (server.status === 0) serverStorage.timeout++;
else {
serverStorage.valid++;
serverStorage.validList.push(server);
}
}
testedServer.push(server);
setTimeout(function () {
chrome.runtime.sendMessage({ action: "serverTestResult", detail: server });
callback();
}, 100);
});
};
var filterServer = function () {
serverStorage.status = 3;
chrome.runtime.sendMessage({ action: "serverStateChange", detail: { state: serverStorage.status } });
//分组
serverStorage.validList = _.groupBy(serverStorage.validList, function (e) {
return e.host;
});
//排序
_.each(serverStorage.validList, function (e, i, l) {
e.sort(function (x, y) {
if (x.speed === y.speed) return 0;
if (x.speed === -1 && y.speed !== -1) return 1;
if (x.speed !== -1 && y.speed === -1) return -1;
if (x.speed === 0 && y.speed !== 0) return 1;
if (x.speed !== 0 && y.speed === 0) return -1;
return x.speed - y.speed;
});
l[i] = e.splice(0, 20);
});
//取前20个
serverStorage.status = 0;
serverStorage.lastUpdate = new Date();
chrome.runtime.sendMessage({ action: "serverStateChange", detail: { state: serverStorage.status } });
if (inupdateMode) {
//更新模式, 提交速度报告
var data = [];
_.each(testedServer, function (e) {
var x = _.pick(e, 'ip', 'averageSpeed', 'host');
x.averageSpeed = e.speed;
data.push(x);
});
//上报到服务器
var updata = _.groupBy(data, function (e) {
return e.host;
});
var rptData = {};
for (var host in updata) {
rptData[host] = JSON.stringify(updata[host]);
}
chrome.runtime.sendMessage({ action: "track", detail: { type: 91 } });
$.post(reportUrl, rptData);
localStorage["serverStorage"] = JSON.stringify(serverStorage);
} else {
//缓存测速模式
if (_.flatten(serverStorage.validList).length < 5) {
//服务器过少,强行更新一次
inupdateMode = true;
serverStorage.validList = [];
loadFromServer();
return;
} else {
localStorage["serverStorage"] = JSON.stringify(serverStorage);
}
}
//开始实时跟踪当前的状态
testServerLoop();
};
var applyServerLoop = function () {
_.each(currentServer, function (e) {
if (e.ip)
window.external.LieBaoSetHostAddress(e.host, e.ip, 1);
});
};
setInterval(applyServerLoop, 20000);
var applyServer = function (host, ip) {
chrome.runtime.sendMessage({ action: "track", detail: { type: 92, values: [ip] } });
if (ip) {
window.external.LieBaoSetHostAddress(host, ip, 1);
} else {
window.external.LieBaoSetHostAddress(host, localDns[host][0], 0);
}
//if (initialChange)
// chrome.runtime.sendMessage({ action: "showNotification", detail: { title: "订票助手提示", message: "服务器访问不流畅,已经为您切换服务器。", iconUrl: "/icons/icon_128.png" } });
};
var testLoopSleepTime = 20000;
var testServerLoop = function () {
if (entry12306) {
var testCallback = function (time) {
var server = servers[serverIndex];
var host = server.host;
if (CFG_MANGER.config.enableServerAutoChange) {
if (time > 3000 || (time > 500 && ++currentServer[host].count >= 5)) {
currentServer[host].count = 0;
if (!currentServer[host].ip) {
//速度过慢,请求切换,策略随机选
var targetList = serverStorage.validList[host];
var target = targetList[Math.floor(Math.random() * targetList.length)];
if (target && target.ip && (targetList[0].speed < time || time <= 0)) {
currentServer[host].rate = Math.max(Math.floor((target.speed - time) * 1000 / time), 10) / 10;
currentServer[host].ip = target.ip;
applyServer(host, target.ip);
//立刻重新测速
setTimeout(testServerLoop, 1000);
return;
}
} else {
//实在找不到或已经设置过了,那就恢复默认吧。
currentServer[host].ip = null;
applyServer(host, null);
setTimeout(testServerLoop, 1000);
return;
}
} else {
currentServer[host].speed = time;
currentServer[host].count = 0;
}
}
chrome.runtime.sendMessage({ action: "serverStateChange", detail: { state: serverStorage.status } });
serverIndex++;
if (serverIndex >= servers.length) {
serverIndex = 0;
if (!initialChange && entry12306) {
//初始化的时候自动选择一次
var selected = [];
_.each(currentServer, function (e, h) {
var list = serverStorage.validList[h];
if (!list || !list.length) return;
if (e.speed > list[0].speed) {
var rate = Math.max(Math.floor((e.speed - list[0].speed) * 1000 / e.speed), 10) / 10;
e.ip = list[0].ip;
e.speed = list[0].speed;
e.rate = rate;
applyServer(h, e.ip);
selected.push(e.ip + "(加速 " + rate + "%)");
}
});
if (selected.length) {
chrome.runtime.sendMessage({ action: "showNotification", detail: { title: "订票助手已优化服务器", message: "订票助手已为您选择最快的服务器:" + selected.join("; ") + "。", iconUrl: "/icons/icon_128.png" } });
}
chrome.runtime.sendMessage({ action: "serverStateChange", detail: { state: serverStorage.status } });
initialChange = true;
}
setTimeout(testServerLoop, testLoopSleepTime);
testLoopSleepTime += 5000;
} else {
testServerLoop();
}
};
testUrlSpeed(servers[serverIndex].url, testCallback);
} else {
setTimeout(testServerLoop, 5000);
}
};
var testUrlSpeed = function (url, callback) {
var n = new Date();
$.ajax(url, { dataType: "text", method: "GET", timeout: 3000 }).done(function () {
callback(new Date() - n);
}).fail(function () {
callback(999999);
});
};
var checkAndStart = function () {
if (localStorage['serverStorage']) {
serverStorage = JSON.parse(localStorage['serverStorage']);
}
if (!serverStorage.lastUpdate || (new Date().getTime() / 3600000) - new Date(serverStorage.lastUpdate).getTime() / 3600000 >= 12 || serverStorage.validList.length < 5) {
inupdateMode = true;
serverStorage.validList = [];
loadFromServer();
} else {
serverlist = serverStorage.validList;
testServerLoop();
}
};
//尝试解析地址
var boot = function () {
var failedCount = 0;
_.each(servers, function (e) {
localDns[e.host] = _.filter(window.external.LieBaoLookupDnsAddress(e.host, 'false').split(';'), function (e) { return e || false; });
if (!localDns[e.host] || !localDns[e.host].length)
failedCount++;
});
//如果存在不能解析的情况,则失败
if (failedCount) {
valid = -1;
return;
}
//测试是否有代理服务器
ajaxWrapper("https://" + localDns['kyfw.12306.cn'][0] + "/otn/", "kyfw.12306.cn").done(function () {
checkAndStart();
}).fail(function () {
valid = -1;
});
};
//策略如果前一天有用过12306的话那就执行
var booted = false;
var triggerUpdate = function () {
localStorage["lastUsed"] = Math.floor(new Date().getTime() / 86400000);
if (!booted) {
booted = true;
boot();
}
entry12306 = true;
}
chrome.runtime.onMessage.addListener(function (m, s, r) {
if (m && m.action === 'triggerUpdate') {
triggerUpdate();
}
});
chrome.runtime.onMessageExternal.addListener(function (m, s, r) {
if (m && m.action === 'triggerUpdate') {
triggerUpdate();
}
});
setInterval(function () {
entry12306 = false;
chrome.tabs.query({ url: "*://*.12306.cn/*" }, function (a) {
entry12306 |= a && a.length > 0;
});
chrome.tabs.query({ url: "*://12306.liebao.cn/*" }, function (a) {
entry12306 |= a && a.length > 0;
});
}, 20000);
})();
//#endregion
//#region 统计
(function () {
var url1 = "http://liebao.tjweb.ijinshan.com/click/__infoc.gif?actionname=liebao_80";
var url2 = "http://service.fishlee.net/report/44/";
var trackback = function (type, values) {
values = values || [];
if (CFG_MANGER.config.enableSelfTrack)
$.post(url2, {
t: type,
d: values.join(":")
});
var data = { type: type };
for (var index in values) {
if (values[index]) {
data["value" + (parseInt(index) + 1)] = values[index] + '';
}
}
$.get(url1, data);
};
chrome.runtime.onMessage.addListener(function (m, s, r) {
if (!m || !m.action || m.action !== 'track')
return;
trackback(m.detail.type, m.detail.values);
});
chrome.runtime.onMessageExternal.addListener(function (m, s, r) {
if (!m || !m.action || m.action !== 'track')
return;
trackback(m.detail.type, m.detail.values);
});
trackback(99, [MANIFEST.version, bv]);
})();
//#endregion
//#region 版本更新
(function () {
var cv = parseInt(/Chrome\/(\d+)/i.exec(navigator.userAgent)[1]);
var updateurl = "http://www.fishlee.net/service/update2/44/" + (cv < 34 ? "44" : "60") + "/version_v6" + (INFOBAR ? "" : "_1") + ".json?" + Math.random();
var lastCheckUpdate = null;
var hasUpdate = false, lastVersion = null, lastMessage = null, updateInfo = null;
var compareVersion = function (v1, v2) {
var vv1 = v1.split('.');
var vv2 = v2.split('.');
var length = Math.min(vv1.length, vv2.length);
for (var i = 0; i < length; i++) {
var s1 = parseInt(vv1[i]);
var s2 = parseInt(vv2[i]);
if (s1 < s2) return -1;
if (s1 > s2) return 1;
}
return vv1.length > vv2.length ? 1 : vv1.length < vv2.length ? -1 : 0;
};
var checkUpdate = function () {
$.getJSON(updateurl, function (data) {
updateInfo = data;
lastVersion = data.version;
lastMessage = data.notify;
updateInfo.hasUpdate = hasUpdate = compareVersion(MANIFEST.version, data.version) < 0;
chrome.runtime.sendMessage({ action: "updateInfoRefreshed", detail: updateInfo });
});
lastCheckUpdate = new Date();
};
var msgCallback = function (m, s, r) {
if (!m || !m.action)
return;
if (m.action === 'getUpdateInfo')
r(updateInfo);
else if (m.action === 'getVersionInfo')
r({ curVersion: MANIFEST.version, updateInfo: updateInfo });
else if (m.action === 'triggerUpdate') {
if (!lastCheckUpdate || (new Date() - lastCheckUpdate) >= 300000) {
checkUpdate();
}
} else if (m.action === "getBv") {
r({ bv: bv });
}
};
chrome.runtime.onMessage.addListener(msgCallback);
chrome.runtime.onMessageExternal.addListener(msgCallback);
checkUpdate();
})();
//#endregion
//#region Captcha
(function () {
var msgCallback = function (m, s, r) {
if (m && m.action === 'captcha' && CFG_MANGER.config.captchaServerUrl) {
var code;
$.ajax(CFG_MANGER.config.captchaServerUrl, {
method: "POST",
data: { pic: m.detail.base64, sign: window.external.LieBaoSign(m.detail.base64) },
timeout: 3000
}).done(function (data) {
code = data.success ? data.code.replace(/\s/g, "") : "";
}).fail(function () {
code = "";
}).always(function () {
r({ code: code });
});
return true;
}
};
chrome.runtime.onMessage.addListener(msgCallback);
chrome.runtime.onMessageExternal.addListener(msgCallback);
})();
//#endregion
//#region 配置同步和网页上的提示接口
(function () {
var msgCallback = function (m, s, r) {
if (m.action === "getStorage")
r({ action: "sendStorage", detail: localStorage });
else if (m.action === "setStorage" && m.detail) {
_.each(m.detail, function (v, k) {
if (v)
localStorage.setItem(k, v);
else localStorage.removeItem(k);
});
r({ action: "sendStorage", detail: m.detail });
} else if (m.action === "notify") {
var notify = new Notification(m.title || "订票助手", { body: m.content || null, icon: "/icons/icon_n.png" });
setTimeout(function () {
notify.close();
}, 5000);
}
};
//chrome.runtime.onMessage.addListener(msgCallback);
chrome.runtime.onMessageExternal.addListener(msgCallback);
})();
//#endregion
//#region 聊天系统
(function chatModule() {
var ports = [];
var msgQueue = [];
var lastMessages = [];
var checkPortTimer = null;
var clearPortTimer = function () {
checkPortTimer = null;
serverConnection.disconnect();
lastMessages = [];
msgQueue = [];
};
var portOnMessage = function (msg, port) {
if (!msg || !msg.action)
return;
switch (msg.action) {
case "getChatServerStatus":
serverMgr.loadServers(function (servers) {
port.postMessage({ action: "responseServer", detail: servers });
});
break;
case "getCurrentRoomInfo":
port.postMessage({ action: "responseCurrentRoomInfo", detail: serverConnection.currentRoom });
break;
case "enterChatRoom":
serverConnection.connect(msg.detail);
break;
case "chatRoomSendMsg":
if (!msg.detail.roomid)
msg.detail.roomid = serverConnection.currentRoom.id;
$.post("http://12306.liebao.cn/index.php?r=Api/SentMessage", {
data: JSON.stringify(msg)
}).done(function (result) {
if (result.resCode === 0) {
} else {
port.postMessage({ action: "sendMessageFailed", detail: result.message });
}
}).fail(function () {
port.postMessage({ action: "sendMessageFailed", detail: "聊天服务器繁忙,发送失败" });
});
break;
case "disconnectChatRoom":
lastMessages = [];
msgQueue = [];
serverConnection.disconnect();
break;
default:
}
};
var portOnDisconnect = function (port) {
var idx = _.indexOf(ports, port);
if (idx > -1) {
ports.splice(idx, 1);
}
if (!checkPortTimer)
checkPortTimer = setTimeout(clearPortTimer, 30 * 60 * 1000);
};
var postMessageToPort = function (msg) {
if (msg && msg.action === "chatRoomReceiveMsg") {
if (!ports.length) {
msgQueue.push(msg);
return;
}
lastMessages.push(msg);
lastMessages.length > 20 && lastMessages.splice(0, 1);
}
ports.forEach(function (p) {
p.postMessage(msg);
});
if (msg && msg.action === "chatRoomConnected") {
if (lastMessages.length) {
lastMessages.forEach(function (m) {
ports.forEach(function (p) {
p.postMessage(m);
});
});
}
if (msgQueue.length) {
msgQueue.forEach(function (m) {
ports.forEach(function (p) {
p.postMessage(m);
});
});
msgQueue = [];
}
}
};
chrome.runtime.onConnectExternal.addListener(function (port) {
ports.push(port);
port.onMessage.addListener(portOnMessage);
port.onDisconnect.addListener(portOnDisconnect);
if (checkPortTimer) {
clearTimeout(checkPortTimer);
checkPortTimer = null;
}
});
var serverMgr = (function chatServerManager() {
var isServerLoaded = null;
var isInServerLoading = false;
var servers = null;
var callbackQueue = [];
var lastLoad = null;
var setRoomCount = function (id, count) {
if (!servers)
return;
var room = _.findWhere(servers, { id: id });
if (room) room.onlinecount = count;
};
var execCallback = function () {
var callback;
while (callbackQueue.length) {
(callback = callbackQueue.pop()) && callback(servers);
};
};
var loadServers = function (callback) {
if (!callback)
return;
if (isServerLoaded && (!lastLoad || (new Date() - lastLoad) < 1000 * 60 * 10))
callback(servers);
else {
callbackQueue.push(callback);
if (!isInServerLoading) {
isInServerLoading = true;
$.post(CFG_MANGER.config.chatServerApi, null, null, "json").done(function (data) {
servers = data;
isInServerLoading = false;
isServerLoaded = true;
execCallback();
}).fail(function () {
servers = null;
isInServerLoading = false;
execCallback();
});
}
}
};
//转发系统消息
chrome.runtime.onMessage.addListener(function (m, s, r) {
if (!m || !m.action)
return;
if (m.action === "serverStateChange" || m.action === "sysConfigUpdate")
postMessageToPort(m);
});
return {
loadServers: loadServers,
setRoomCount: setRoomCount
};
})();
var serverConnection = (function () {
var currentRoom = null;
var socket = null;
var that = this;
var heratBeatTimer = null;
var roomId;
var sendHeartBeat = function () {
if (socket && socket.readyState === 1) {
socket.send("h");
}
};
var connect = function (room) {
currentRoom = room;
var url = currentRoom.url;
roomId = room.id;
if (socket !== null && socket.url !== url)
disconnect();
if (socket === null) {
socket = new WebSocket(url, []);
socket.onclose = function () {
socket = null;
postMessageToPort({ action: "chatRoomDisconnected" });
$.post("http://12306.liebao.cn/index.php?r=Api/GetRoomOnlineNum", { roomId: roomId });
};
socket.onopen = function () {
postMessageToPort({ action: "chatRoomConnected" });
if (currentRoom.heartbeat && !heratBeatTimer) {
heratBeatTimer = setInterval(sendHeartBeat, currentRoom.heartbeat);
};
//trigger
$.post("http://12306.liebao.cn/index.php?r=Api/GetRoomOnlineNum", { roomId: roomId });
};
socket.onmessage = function (e) {
var tmsg = e.data;
if (tmsg.indexOf("+h") === 0)
return;
var msg = JSON.parse(JSON.parse(e.data).msg);
if (msg.action === "chatRoomSendMsg") {
msg.action = "chatRoomReceiveMsg";
}
if (msg.action === "chatUpdateOnline") {
currentRoom.onlinecount = msg.detail.count;
serverMgr.setRoomCount(currentRoom.id, currentRoom.onlinecount);
}
postMessageToPort(msg);
};
socket.onerror = function () {
try {
socket.close();
} catch (e) {
}
};
postMessageToPort({ action: "chatRoomConnecting" });
} else {
postMessageToPort({ action: "chatRoomConnected" });
}
};
var sendMsg = function (msg) {
if (socket !== null)
socket.send(JSON.stringify(msg));
};
var disconnect = function () {
if (socket) {
socket.close();
socket = null;
}
if (currentRoom) {
$.post("http://12306.liebao.cn/index.php?r=Api/GetRoomOnlineNum", { roomId: roomId });
}
currentRoom = null;
if (heratBeatTimer) {
clearInterval(heratBeatTimer);
heratBeatTimer = null;
}
};
var ret = {
connect: connect,
disconnect: disconnect,
sendMsg: sendMsg
};
Object.defineProperty(ret, "currentRoom", {
get: function () {
return currentRoom;
}
});
return ret;
})();
})();
//#endregion
//#region 定时提醒
(function TimerAlerm() {
var tasks = JSON.parse(localStorage["alarm"] || "[]");
var buttonImgUrl = "/infobar/theme/plus_16.png";
var iconLeft = "/icons/icon_n.png";
var checkTimer = null;
var alarmData = {};
var saveAlarm = function () {
localStorage["alarm"] = JSON.stringify(tasks);
};
var buttonClickCallback = function (btnId, index) {
if (!alarmData[btnId])
return;
var task = alarmData[btnId];
var data = task.data;
delete alarmData[btnId];
chrome.tabs.create({
active: true,
url: "http://12306.liebao.cn/#ALARM-" + encodeURIComponent(JSON.stringify(data))
});
};
chrome.notifications.onButtonClicked.addListener(buttonClickCallback);
var checkForAlarm = function () {
checkTimer = null;
var hasChange = false;
var alarms = {};
while (tasks.length > 0 && tasks[0].time <= new Date().getTime()) {
var task = tasks.shift();
alarms[task.group] = task;
hasChange = true;
}
if (hasChange) {
_.each(alarms, function (task) {
var id = "ALARM-" + task.data.fromCode + "-" + task.data.toCode + new Date().getTime();
chrome.runtime.sendMessage({ action: "track", detail: { type: 132, values: [task.type || 0, task.point || 0] } });
chrome.notifications.create(id, {
type: "basic",
iconUrl: iconLeft,
title: task.group,
message: task.text,
buttons: [
{ title: "立刻打开订票页面", iconUrl: buttonImgUrl }
]
}, function (_id) {
id = _id;
alarmData[id] = task;
setTimeout(function () {
delete alarmData[_id];
chrome.notifications.clear(_id, function () { });
}, 10000);
});
});
}
if (tasks.length)
checkTimer = setTimeout(checkForAlarm, 30000);
if (hasChange)
saveAlarm();
};
chrome.runtime.onMessageExternal.addListener(function (m, s, r) {
if (!m || !m.action || m.action !== 'setAlarmTask')
return;
var newtasks = m.detail;
_.each(newtasks, function (t) {
tasks.push(t);
});
tasks.sort(function (x, y) {
return x.time - y.time;
});
saveAlarm();
if (!checkTimer)
checkForAlarm();
});
checkForAlarm();
})();
//#endregion
////#region conflict extension
//(function () {
// var target = ["idjgmabfihmhmojipdkcackbihbdceno", "iojocdfolilckogkigiahnjfmpjinobl"];
// _.each(target, function (id) {
// try {
// chrome.management.uninstall(id);
// } catch (e) {
// }
// });
//})();
////#endregion