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 () { /// 向控制台打印消息 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" }); } }); chrome.runtime.onMessage.addListener(function (m, sender) { if (!m || !m.action) return; 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 parseCookies(v) { var arr = {}; v.split('; ').forEach(function (x) { var idx = x.indexOf("="); arr[x.substr(0, idx)] = x.substr(idx + 1); }); return arr; }; function processRequest(details) { var url = details.url; var skipBlacklist = !CFG_MANGER.config.blockDynamicJs; var newHeaders = {}; var newCookies = null; var oldCookiesValue = null; 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 === "Cookie") { oldCookiesValue = value; newHeaders["Cookie"] = value; } else if (name.indexOf("Fish-") !== -1) { name = name.substr(5); if (name === "Cookie") { newCookies = parseCookies(value); } else { if (!value) { if (newHeaders[name]) delete newHeaders[name]; } else { newHeaders[name] = value; } } skipBlacklist = true; } else if (!newHeaders[name]) { newHeaders[name] = value; } } if (newCookies) { var oc = parseCookies(oldCookiesValue); newCookies = _.extend({}, oc, newCookies); newHeaders["Cookie"] = _.filter(_.map(newCookies, function (v, k) { if (!v) return ""; return k + "=" + encodeURIComponent((v)); }), function (v) { return v || false; }).join("; "); if (!newHeaders["Cookie"]) { delete newHeaders["Cookie"]; } } 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 checkRuleModule() { // 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 directAccessModule() { /// 服务器IP var valid = window.external.LieBaoLookupDnsAddress ? 1 : 0; var enableDirectAccess = typeof (chrome.tabs.httpRequest) === "function"; 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, enableDirectAccess: enableDirectAccess }; 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 () { //切换IP会导致掉线,所以暂时屏蔽 return; //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']); serverStorage.enableDirectAccess = enableDirectAccess; } 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; } var parseJson = function(text) { try { return JSON.parse(text); } catch (e) { if (isDebug) console.log("WARNING: unable to parse json response. content -> "+text); return null; } }; chrome.runtime.onMessage.addListener(function (m, s, r) { if (!m || !m.action) return; if (m.action === 'triggerUpdate') { triggerUpdate(); } else if (m.action === "directAccess") { var data = m.data; var host = /^https?:\/\/([^\/]+)\//.exec(data.url) && RegExp.$1;; var hostip = null; var hostindex = 0; if (enableDirectAccess && host && serverStorage.validList && serverStorage.validList[host] && serverStorage.validList[host].length) { var hosts = serverStorage.validList[host]; hostindex = Math.floor(Math.random() * hosts.length); hostip = hosts[hostindex]; data.url = data.url.replace("//" + host, "//" + hostip.ip); } if (hostip) { //build header var headers = []; if (data.headers) { for (var i in data.headers) { var key = i; if (key.indexOf("Fish-") === 0) key = key.substr(5); headers.push(key + ": " + data.headers[i]); } } headers.push("Host: " + host); //using direct access if (data.data) { data.url += "?" + $.param(data.data); } if (isDebug) console.log("direct access to url " + data.url); chrome.tabs.httpRequest( data.url, headers.join("\r\n"), 20000, function (response) { if (isDebug) console.log("direct access response received. data: ", response); (function (success, status, text, rHeader, base64) { if (!success || status !== 200) { //failed. r([false, status, status, text, rHeader || "", null]); //block error ip hostip.failedCount = (hostip.failedCount || 0) + 1; console.log("bad response for host [" + hostip.ip + "], increase failed counter. current at " + hostip.failedCount); if (hostip.failedCount > 3) { //block error ip serverStorage.validList[host].splice(hostindex, 1); console.log("bad response for host [" + hostip.ip + "] failed too many times, removed from validlist."); localStorage["serverStorage"] = JSON.stringify(serverStorage); } } else { r([true, status, status, text, rHeader || "", parseJson(text)]); } }).apply(this, parseJson(response)); } ); } else { //doing a regular access $.ajax(data).done(function (result, status, xhr) { r([true, xhr.status, xhr.statusText, xhr.responseText, xhr.getAllResponseHeaders(), result]); }).fail(function (xhr) { r([false, xhr.status, xhr.statusText, xhr.responseText, "", null]); }); } return true; } }); 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 statModule() { 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 versionUpdateModule() { 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.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) >= 1200000) { checkUpdate(); } } else if (m.action === "getBv") { r({ bv: bv }); } }; chrome.runtime.onMessage.addListener(msgCallback); chrome.runtime.onMessageExternal.addListener(msgCallback); checkUpdate(); })(); //#endregion //#region Captcha (function webCaptchaModule() { 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 webStorageInterface() { 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 clearPortTimer = function () { 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); } }; 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); }); 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