Export timetable data as lua table.
// ==UserScript==
// @name timetable2lua
// @namespace https://dvxg.de/
// @version 0.2.6
// @author davidxuang
// @description Export timetable data as lua table.
// @license AGPL-3.0-only
// @icon https://cdn.jsdelivr.net/gh/microsoft/fluentui-emoji/assets/Metro/3D/metro_3d.png
// @homepage https://github.com/davidxuang/timetable2lua
// @homepageURL https://github.com/davidxuang/timetable2lua
// @match https://www.cqmetro.cn/smbsj/
// @match https://www.wuhanrt.com/news-content.html*
// ==/UserScript==
(function() {
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
key = keys[i];
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
get: ((k) => from[k]).bind(null, key),
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
});
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
value: mod,
enumerable: true
}) : target, mod));
function t(t) {
return t && t.__esModule && Object.prototype.hasOwnProperty.call(t, "default") ? t.default : t;
}
var r, e, n, o, u, f, i = { exports: {} }, c = { exports: {} };
function l() {
return r || (r = 1, function(t) {
var r = function() {
function t(r, n, o, u) {
"object" == typeof n && (o = n.depth, u = n.prototype, n.filter, n = n.circular);
var f = [], i = [], c = "undefined" != typeof Buffer;
return void 0 === n && (n = !0), void 0 === o && (o = Infinity), function r(o, l) {
if (null === o) return null;
if (0 == l) return o;
var s, a;
if ("object" != typeof o) return o;
if (t.__isArray(o)) s = [];
else if (t.__isRegExp(o)) s = new RegExp(o.source, e(o)), o.lastIndex && (s.lastIndex = o.lastIndex);
else if (t.__isDate(o)) s = new Date(o.getTime());
else {
if (c && Buffer.isBuffer(o)) return s = Buffer.allocUnsafe ? Buffer.allocUnsafe(o.length) : new Buffer(o.length), o.copy(s), s;
void 0 === u ? (a = Object.getPrototypeOf(o), s = Object.create(a)) : (s = Object.create(u), a = u);
}
if (n) {
var p = f.indexOf(o);
if (-1 != p) return i[p];
f.push(o), i.push(s);
}
for (var g in o) {
var y;
a && (y = Object.getOwnPropertyDescriptor(a, g)), y && null == y.set || (s[g] = r(o[g], l - 1));
}
return s;
}(r, o);
}
function r(t) {
return Object.prototype.toString.call(t);
}
function e(t) {
var r = "";
return t.global && (r += "g"), t.ignoreCase && (r += "i"), t.multiline && (r += "m"), r;
}
return t.clonePrototype = function(t) {
if (null === t) return null;
var r = function() {};
return r.prototype = t, new r();
}, t.__objToStr = r, t.__isDate = function(t) {
return "object" == typeof t && "[object Date]" === r(t);
}, t.__isArray = function(t) {
return "object" == typeof t && "[object Array]" === r(t);
}, t.__isRegExp = function(t) {
return "object" == typeof t && "[object RegExp]" === r(t);
}, t.__getRegExpFlags = e, t;
}();
t.exports && (t.exports = r);
}(c)), c.exports;
}
function s() {
if (n) return e;
n = 1;
var t = l();
return e = function(r, e) {
return r = r || {}, Object.keys(e).forEach((function(n) {
void 0 === r[n] && (r[n] = t(e[n]));
})), r;
};
}
function a() {
return u ? o : (u = 1, o = [
[768, 879],
[1155, 1158],
[1160, 1161],
[1425, 1469],
[1471, 1471],
[1473, 1474],
[1476, 1477],
[1479, 1479],
[1536, 1539],
[1552, 1557],
[1611, 1630],
[1648, 1648],
[1750, 1764],
[1767, 1768],
[1770, 1773],
[1807, 1807],
[1809, 1809],
[1840, 1866],
[1958, 1968],
[2027, 2035],
[2305, 2306],
[2364, 2364],
[2369, 2376],
[2381, 2381],
[2385, 2388],
[2402, 2403],
[2433, 2433],
[2492, 2492],
[2497, 2500],
[2509, 2509],
[2530, 2531],
[2561, 2562],
[2620, 2620],
[2625, 2626],
[2631, 2632],
[2635, 2637],
[2672, 2673],
[2689, 2690],
[2748, 2748],
[2753, 2757],
[2759, 2760],
[2765, 2765],
[2786, 2787],
[2817, 2817],
[2876, 2876],
[2879, 2879],
[2881, 2883],
[2893, 2893],
[2902, 2902],
[2946, 2946],
[3008, 3008],
[3021, 3021],
[3134, 3136],
[3142, 3144],
[3146, 3149],
[3157, 3158],
[3260, 3260],
[3263, 3263],
[3270, 3270],
[3276, 3277],
[3298, 3299],
[3393, 3395],
[3405, 3405],
[3530, 3530],
[3538, 3540],
[3542, 3542],
[3633, 3633],
[3636, 3642],
[3655, 3662],
[3761, 3761],
[3764, 3769],
[3771, 3772],
[3784, 3789],
[3864, 3865],
[3893, 3893],
[3895, 3895],
[3897, 3897],
[3953, 3966],
[3968, 3972],
[3974, 3975],
[3984, 3991],
[3993, 4028],
[4038, 4038],
[4141, 4144],
[4146, 4146],
[4150, 4151],
[4153, 4153],
[4184, 4185],
[4448, 4607],
[4959, 4959],
[5906, 5908],
[5938, 5940],
[5970, 5971],
[6002, 6003],
[6068, 6069],
[6071, 6077],
[6086, 6086],
[6089, 6099],
[6109, 6109],
[6155, 6157],
[6313, 6313],
[6432, 6434],
[6439, 6440],
[6450, 6450],
[6457, 6459],
[6679, 6680],
[6912, 6915],
[6964, 6964],
[6966, 6970],
[6972, 6972],
[6978, 6978],
[7019, 7027],
[7616, 7626],
[7678, 7679],
[8203, 8207],
[8234, 8238],
[8288, 8291],
[8298, 8303],
[8400, 8431],
[12330, 12335],
[12441, 12442],
[43014, 43014],
[43019, 43019],
[43045, 43046],
[64286, 64286],
[65024, 65039],
[65056, 65059],
[65279, 65279],
[65529, 65531],
[68097, 68099],
[68101, 68102],
[68108, 68111],
[68152, 68154],
[68159, 68159],
[119143, 119145],
[119155, 119170],
[119173, 119179],
[119210, 119213],
[119362, 119364],
[917505, 917505],
[917536, 917631],
[917760, 917999]
]);
}
var g = t(function() {
if (f) return i.exports;
f = 1;
var t = s(), r = a(), e = {
nul: 0,
control: 0
};
function n(t, r) {
if ("string" != typeof t) return o(t, r);
for (var e = 0, n = 0; n < t.length; n++) {
var u = o(t.charCodeAt(n), r);
if (u < 0) return -1;
e += u;
}
return e;
}
function o(t, e) {
return 0 === t ? e.nul : t < 32 || t >= 127 && t < 160 ? e.control : function(t) {
var e, n = 0, o = r.length - 1;
if (t < r[0][0] || t > r[o][1]) return !1;
for (; o >= n;) if (e = Math.floor((n + o) / 2), t > r[e][1]) n = e + 1;
else {
if (!(t < r[e][0])) return !0;
o = e - 1;
}
return !1;
}(t) ? 0 : 1 + (t >= 4352 && (t <= 4447 || 9001 == t || 9002 == t || t >= 11904 && t <= 42191 && 12351 != t || t >= 44032 && t <= 55203 || t >= 63744 && t <= 64255 || t >= 65040 && t <= 65049 || t >= 65072 && t <= 65135 || t >= 65280 && t <= 65376 || t >= 65504 && t <= 65510 || t >= 131072 && t <= 196605 || t >= 196608 && t <= 262141));
}
return i.exports = function(t) {
return n(t, e);
}, i.exports.config = function(r) {
return r = t(r || {}, e), function(t) {
return n(t, r);
};
}, i.exports;
}());
function y(t, r, e = {}) {
const n = "number" == typeof t;
let o = n ? r : t;
const u = n ? t : r;
"string" == typeof e && (e = { char: e }), e.char || (e.char = " "), e.strip || (e.strip = !1), "string" != typeof o && (o = o.toString());
let f = null, i = "";
if (e.colors) f = o.replace(/\x1B\[(?:[0-9]{1,2}(?:;[0-9]{1,2})?)?[m|K]/g, "");
const c = !0 === e.fixed_width ? u - (f || o).length : u - g.config(e.wcwidth_options || {})(f || o);
return c < 0 ? e.strip ? n ? o.substr(-1 * u) : o.substr(0, u) : o : (i += e.char.repeat(c), n ? i + o : o + i);
}
var require_clone = __commonJSMin(((exports, module) => {
var clone = (function() {
"use strict";
function clone(parent, circular, depth, prototype) {
if (typeof circular === "object") {
depth = circular.depth;
prototype = circular.prototype;
circular.filter;
circular = circular.circular;
}
var allParents = [];
var allChildren = [];
var useBuffer = typeof Buffer != "undefined";
if (typeof circular == "undefined") circular = true;
if (typeof depth == "undefined") depth = Infinity;
function _clone(parent, depth) {
if (parent === null) return null;
if (depth == 0) return parent;
var child;
var proto;
if (typeof parent != "object") return parent;
if (clone.__isArray(parent)) child = [];
else if (clone.__isRegExp(parent)) {
child = new RegExp(parent.source, __getRegExpFlags(parent));
if (parent.lastIndex) child.lastIndex = parent.lastIndex;
} else if (clone.__isDate(parent)) child = new Date(parent.getTime());
else if (useBuffer && Buffer.isBuffer(parent)) {
if (Buffer.allocUnsafe) child = Buffer.allocUnsafe(parent.length);
else child = new Buffer(parent.length);
parent.copy(child);
return child;
} else if (typeof prototype == "undefined") {
proto = Object.getPrototypeOf(parent);
child = Object.create(proto);
} else {
child = Object.create(prototype);
proto = prototype;
}
if (circular) {
var index = allParents.indexOf(parent);
if (index != -1) return allChildren[index];
allParents.push(parent);
allChildren.push(child);
}
for (var i in parent) {
var attrs;
if (proto) attrs = Object.getOwnPropertyDescriptor(proto, i);
if (attrs && attrs.set == null) continue;
child[i] = _clone(parent[i], depth - 1);
}
return child;
}
return _clone(parent, depth);
}
clone.clonePrototype = function clonePrototype(parent) {
if (parent === null) return null;
var c = function() {};
c.prototype = parent;
return new c();
};
function __objToStr(o) {
return Object.prototype.toString.call(o);
}
clone.__objToStr = __objToStr;
function __isDate(o) {
return typeof o === "object" && __objToStr(o) === "[object Date]";
}
clone.__isDate = __isDate;
function __isArray(o) {
return typeof o === "object" && __objToStr(o) === "[object Array]";
}
clone.__isArray = __isArray;
function __isRegExp(o) {
return typeof o === "object" && __objToStr(o) === "[object RegExp]";
}
clone.__isRegExp = __isRegExp;
function __getRegExpFlags(re) {
var flags = "";
if (re.global) flags += "g";
if (re.ignoreCase) flags += "i";
if (re.multiline) flags += "m";
return flags;
}
clone.__getRegExpFlags = __getRegExpFlags;
return clone;
})();
if (typeof module === "object" && module.exports) module.exports = clone;
}));
var require_defaults = __commonJSMin(((exports, module) => {
var clone = require_clone();
module.exports = function(options, defaults) {
options = options || {};
Object.keys(defaults).forEach(function(key) {
if (typeof options[key] === "undefined") options[key] = clone(defaults[key]);
});
return options;
};
}));
var require_combining = __commonJSMin(((exports, module) => {
module.exports = [
[768, 879],
[1155, 1158],
[1160, 1161],
[1425, 1469],
[1471, 1471],
[1473, 1474],
[1476, 1477],
[1479, 1479],
[1536, 1539],
[1552, 1557],
[1611, 1630],
[1648, 1648],
[1750, 1764],
[1767, 1768],
[1770, 1773],
[1807, 1807],
[1809, 1809],
[1840, 1866],
[1958, 1968],
[2027, 2035],
[2305, 2306],
[2364, 2364],
[2369, 2376],
[2381, 2381],
[2385, 2388],
[2402, 2403],
[2433, 2433],
[2492, 2492],
[2497, 2500],
[2509, 2509],
[2530, 2531],
[2561, 2562],
[2620, 2620],
[2625, 2626],
[2631, 2632],
[2635, 2637],
[2672, 2673],
[2689, 2690],
[2748, 2748],
[2753, 2757],
[2759, 2760],
[2765, 2765],
[2786, 2787],
[2817, 2817],
[2876, 2876],
[2879, 2879],
[2881, 2883],
[2893, 2893],
[2902, 2902],
[2946, 2946],
[3008, 3008],
[3021, 3021],
[3134, 3136],
[3142, 3144],
[3146, 3149],
[3157, 3158],
[3260, 3260],
[3263, 3263],
[3270, 3270],
[3276, 3277],
[3298, 3299],
[3393, 3395],
[3405, 3405],
[3530, 3530],
[3538, 3540],
[3542, 3542],
[3633, 3633],
[3636, 3642],
[3655, 3662],
[3761, 3761],
[3764, 3769],
[3771, 3772],
[3784, 3789],
[3864, 3865],
[3893, 3893],
[3895, 3895],
[3897, 3897],
[3953, 3966],
[3968, 3972],
[3974, 3975],
[3984, 3991],
[3993, 4028],
[4038, 4038],
[4141, 4144],
[4146, 4146],
[4150, 4151],
[4153, 4153],
[4184, 4185],
[4448, 4607],
[4959, 4959],
[5906, 5908],
[5938, 5940],
[5970, 5971],
[6002, 6003],
[6068, 6069],
[6071, 6077],
[6086, 6086],
[6089, 6099],
[6109, 6109],
[6155, 6157],
[6313, 6313],
[6432, 6434],
[6439, 6440],
[6450, 6450],
[6457, 6459],
[6679, 6680],
[6912, 6915],
[6964, 6964],
[6966, 6970],
[6972, 6972],
[6978, 6978],
[7019, 7027],
[7616, 7626],
[7678, 7679],
[8203, 8207],
[8234, 8238],
[8288, 8291],
[8298, 8303],
[8400, 8431],
[12330, 12335],
[12441, 12442],
[43014, 43014],
[43019, 43019],
[43045, 43046],
[64286, 64286],
[65024, 65039],
[65056, 65059],
[65279, 65279],
[65529, 65531],
[68097, 68099],
[68101, 68102],
[68108, 68111],
[68152, 68154],
[68159, 68159],
[119143, 119145],
[119155, 119170],
[119173, 119179],
[119210, 119213],
[119362, 119364],
[917505, 917505],
[917536, 917631],
[917760, 917999]
];
}));
var import_wcwidth = __toESM(__commonJSMin(((exports, module) => {
var defaults = require_defaults();
var combining = require_combining();
var DEFAULTS = {
nul: 0,
control: 0
};
module.exports = function wcwidth(str) {
return wcswidth(str, DEFAULTS);
};
module.exports.config = function(opts) {
opts = defaults(opts || {}, DEFAULTS);
return function wcwidth(str) {
return wcswidth(str, opts);
};
};
function wcswidth(str, opts) {
if (typeof str !== "string") return wcwidth(str, opts);
var s = 0;
for (var i = 0; i < str.length; i++) {
var n = wcwidth(str.charCodeAt(i), opts);
if (n < 0) return -1;
s += n;
}
return s;
}
function wcwidth(ucs, opts) {
if (ucs === 0) return opts.nul;
if (ucs < 32 || ucs >= 127 && ucs < 160) return opts.control;
if (bisearch(ucs)) return 0;
return 1 + (ucs >= 4352 && (ucs <= 4447 || ucs == 9001 || ucs == 9002 || ucs >= 11904 && ucs <= 42191 && ucs != 12351 || ucs >= 44032 && ucs <= 55203 || ucs >= 63744 && ucs <= 64255 || ucs >= 65040 && ucs <= 65049 || ucs >= 65072 && ucs <= 65135 || ucs >= 65280 && ucs <= 65376 || ucs >= 65504 && ucs <= 65510 || ucs >= 131072 && ucs <= 196605 || ucs >= 196608 && ucs <= 262141));
}
function bisearch(ucs) {
var min = 0;
var max = combining.length - 1;
var mid;
if (ucs < combining[0][0] || ucs > combining[max][1]) return false;
while (max >= min) {
mid = Math.floor((min + max) / 2);
if (ucs > combining[mid][1]) min = mid + 1;
else if (ucs < combining[mid][0]) max = mid - 1;
else return true;
}
return false;
}
}))(), 1);
function assert(condition, message) {
if (!condition) throw new Error(message || "Assertion failed");
}
function attachButton(parent, onClick) {
const button = document.createElement("a");
button.append("导出");
button.addEventListener("click", onClick, false);
button.style.cursor = "pointer";
button.style.position = "absolute";
button.style.zIndex = "1";
button.style.color = "white";
button.style.opacity = ".75";
button.style.paddingInlineStart = ".5em";
button.style.fontSize = ".84em";
parent?.appendChild(button);
}
function compareNestedStringArray(x, y) {
if (x instanceof Array) if (x.length != y.length) return false;
else return x.filter((v, i) => !compareNestedStringArray(v, y[i])).length == 0;
else return x === y;
}
function deduplicateDays(timetable) {
let dedup = true;
timetable.forEach((days) => {
if (days.length > 1) days.slice(1).forEach((day) => {
if (!compareNestedStringArray(days[0], day)) dedup = false;
});
});
if (dedup) return new Map(Array.from(timetable.entries()).map(([station, days]) => [station, [days[0]]]));
else return timetable;
}
function luaifyNestedStringArray(array, padding = 0) {
if (array instanceof Array) return `{ ${array.map((child) => luaifyNestedStringArray(child, padding)).join(", ")} }`;
else if (array == "nil") return y(padding, `nil`);
else return y(padding, `'${array}'`);
}
var Timetable = {
reverse: function(timetable) {
return new Map([...timetable.entries()].reverse().map(([name, times]) => [name, times.map(([first, last]) => [first.reverse(), last.reverse()])]));
},
luaify: function(timetable) {
timetable = deduplicateDays(timetable);
const padding = Math.max(...[...timetable.keys()].map((str) => (0, import_wcwidth.default)(str))) + 4;
return `
\t\t\tstations = ${luaifyNestedStringArray([...timetable.keys()])},
\t\t\tdata = {
${Array.from(timetable).map(([key, value]) => `\t\t\t\t${y(`['${key}']`, padding)} = ${luaifyNestedStringArray(value, 7)},`).join("\n")}
\t\t\t}`;
}
};
function parseCell$1(cell, closed) {
return cell.innerText.trim().replace(/\p{Pd}+/u, closed ? "nil" : "").replace(/^0([4-9]):(\d\d)$/, "$1:$2");
}
function parseRow(cells, days, first, last) {
const closed = cells.slice(1).filter((cell) => cell.innerText.trim().length > 2).length == 0;
return days.map((dayOffset) => [first.map((i) => parseCell$1(cells[i + dayOffset], closed)), last.map((index) => index instanceof Array ? index.map((i) => parseCell$1(cells[i + dayOffset], closed)) : parseCell$1(cells[index + dayOffset], closed))]);
}
function parseRows(rows, days, first, last) {
const timetable = new Map();
for (const row of rows) {
if (row.length == 0) break;
const name = row[0].innerText.trim().replace("航站楼", "");
if (!name || name == "--") break;
timetable.set(name, parseRow(row, days, first, last));
}
return timetable;
}
var CRT = { bootstrap: function() {
document.querySelectorAll(".schedule-card").forEach((card) => {
const caption = [...card.querySelectorAll(".schedule-card-head")].single();
const copyData = function() {
const table = [...card.querySelectorAll("table")].single();
const [thDays, thTimes, thTermini] = (() => {
const rows = table.tHead?.rows;
if (rows?.length == 3) return [
0,
1,
2
].map((r) => [...table.tHead.rows[r].querySelectorAll("th:not([rowspan])")].filter((th) => th.innerText.trim().length > 2));
else if (rows?.length == 2) {
function getCommon(left, right) {
return left.split("").filter((char, c) => char == right[c]).join("");
}
let days;
if (rows[0].cells.length == 5) {
days = [document.createElement("th"), document.createElement("th")];
days[0].innerText = getCommon(rows[0].cells[1].innerText.trim(), rows[0].cells[2].innerText.trim());
days[1].innerText = getCommon(rows[0].cells[3].innerText.trim(), rows[0].cells[4].innerText.trim());
days.forEach((th) => th.setAttribute("colspan", (rows[0].cells[1].colSpan * 2).toString()));
} else throw rows[0].cells;
return [days, ...[0, 1].map((r) => [...table.tHead.rows[r].querySelectorAll("th:not([rowspan])")].filter((th) => th.innerText.trim().length > 2))];
} else throw rows?.[0]?.cells;
})();
if (thDays.length == 0) {
thDays.push(document.createElement("th"));
thDays[0].colSpan = thTimes.map((g) => g.colSpan).reduce((p, c) => p + c, 0);
}
assert([1, 2].includes(thDays.length), "Invalid # of days.");
assert(thTimes.length % thDays.length == 0 && thTimes.length >= 2, "Invalid # of termini.");
assert(thTermini.length % thDays.length == 0 && thTermini.length >= 2, "Invalid # of child termini.");
const dayWidth = thDays[0].colSpan;
const days = [];
for (let i = 0; i < thDays.length; i++) {
assert(thDays[i].colSpan == dayWidth);
days.push(i * dayWidth);
}
const first = [1, 2];
const last = [3, 4];
const dl = [];
const ul = [];
if (thTimes.length / thDays.length == 2 && thTermini.length / thTimes.length == 2) {
if (thTermini[0].innerText.trim().includes(table.tBodies[0].rows[0].cells[0].innerText.trim())) {
first.reverse();
last.reverse();
}
} else if (thTimes.length / thDays.length >= 2) {
let i = 0;
for (const terminus of thTimes) {
const span = thTermini.slice(i, i + terminus.colSpan);
if (terminus.innerText.trim().startsWith("首班车")) {
first[0] = span.single((td) => {
return td.innerText.trim().match(/↓|内环/u) !== null;
}).cellIndex + 1;
first[1] = span.single((td) => {
return td.innerText.trim().match(/↑|外环/u) !== null;
}).cellIndex + 1;
} else {
dl.push(...span.filter((td) => {
return td.innerText.trim().match(/↓|内环/u) !== null;
}).map((td) => td.cellIndex + 1));
ul.push(...span.filter((td) => {
return td.innerText.trim().match(/↑|外环/u) !== null;
}).map((td) => td.cellIndex + 1));
}
i += terminus.colSpan;
if (i >= thDays[0].colSpan) break;
}
[last[0], last[1]] = dl.length == 1 && ul.length == 1 ? [dl[0], ul[0]] : [dl, ul];
} else throw thTimes.length;
let timetable = parseRows([...table.tBodies[0].rows].map((row) => [...row.cells]), days, first, last);
if (caption.innerText.includes("璧铜") && timetable.keys().next().value?.includes("璧山")) timetable = Timetable.reverse(timetable);
navigator.clipboard.writeText(Timetable.luaify(timetable));
};
attachButton(caption, copyData);
new MutationObserver(() => {
if (caption.querySelector("a") == null) {
attachButton(caption, copyData);
const rows = [...[...card.querySelectorAll("table")].single().tBodies[0].rows].map((row) => [...row.cells]);
const i = rows.findIndex((row) => row.every((cell) => cell.innerText.trim().length <= 2));
if (i < 0) return;
const j = rows.findIndex((row, r) => r > i && row.some((cell) => cell.innerText.includes("↓")));
if (j < 0) return;
attachButton(rows[j][0], function() {
const d = rows[j].map((cell, c) => cell.innerText.includes("↓") ? c : null).filter((c) => c !== null);
const u = rows[j].map((cell, c) => cell.innerText.includes("↑") ? c : null).filter((c) => c !== null);
let days;
assert(d.length == u.length && d.length >= 2, "Invalid # of termini.");
const first = [d[0], u[0]];
const last = [d[1], u[1]];
if (d.length == 2) days = [d[0] - 1];
else if (d.length == 4) days = [d[0] - 1, d[2] - 1];
else throw [d, u];
const timetable = parseRows(rows.slice(i + 2), days, first, last);
navigator.clipboard.writeText(Timetable.luaify(timetable));
});
}
}).observe(card, {
childList: true,
subtree: true
});
});
} };
function parseCell(cell) {
return cell.innerText.trim().replace(/\p{Pd}+|[((]到达[))]/u, "");
}
var WHRT = { bootstrap: () => {
const title = document.querySelector("h1");
const copyData = function() {
const timetable = new Map();
document.querySelectorAll("table.Table").forEach((table) => {
const termini = [...table.querySelector("tr:has(td + td)").querySelectorAll("td")];
const sub_termini = [...table.querySelector("tr:not(:has(td[colspan]))").querySelectorAll("td")];
assert(termini.length == 2, "Invalid # of termini.");
const terminiSpans = termini.map((td) => td.colSpan);
assert(terminiSpans[0] >= 3, "Invalid termini span.");
assert(terminiSpans[1] >= 3, "Invalid termini span.");
const offsetFirst = [sub_termini.slice(0, terminiSpans[0]).find((td) => td.innerText.trim().startsWith("首班车")).cellIndex, sub_termini.find((td) => td.innerText.trim().startsWith("首班车")).cellIndex];
const dl = sub_termini.slice(terminiSpans[0]).filter((td) => td.innerText.trim().startsWith("末班车")).map((td) => td.cellIndex);
const ul = sub_termini.slice(0, terminiSpans[0]).filter((td) => td.innerText.trim().startsWith("末班车")).map((td) => td.cellIndex);
const offsetLast = dl.length == 1 && ul.length == 1 ? [dl[0], ul[0]] : [dl, ul];
offsetLast.forEach((o) => {
if (o instanceof Array) o.unshift(o.pop());
});
const nameOffset = sub_termini.slice(terminiSpans[0]).find((td) => td.innerText.trim().startsWith("车站")).cellIndex;
assert(nameOffset > 0, "Invalid name offset.");
const rows = [...table.querySelectorAll("tr:not(:has(td[colspan]))")].slice(1);
for (const row of rows) {
const name = row.cells[nameOffset].innerText.trim();
const up_row = rows[rows.length - 1 - rows.indexOf(row)];
assert(up_row !== void 0, "Invalid row.");
if (!timetable.has(name)) timetable.set(name, []);
timetable.get(name).push([[parseCell(row.cells[offsetFirst[0]]), parseCell(up_row.cells[offsetFirst[1]])], [offsetLast[0] instanceof Array ? offsetLast[0].map((i) => parseCell(row.cells[i])) : parseCell(row.cells[offsetLast[0]]), offsetLast[1] instanceof Array ? offsetLast[1].map((i) => parseCell(up_row.cells[i])) : parseCell(up_row.cells[offsetLast[1]])]]);
}
});
navigator.clipboard.writeText(Timetable.luaify(timetable));
};
attachButton(title, copyData);
} };
if (!Array.prototype.single) Object.defineProperty(Array.prototype, "single", {
value: function(predicate) {
const target = predicate ? this.filter(predicate) : this;
if (target.length === 0) throw new Error("Sequence contains no matching element");
if (target.length > 1) throw new Error("Sequence contains more than one matching element");
return target[0];
},
enumerable: false,
configurable: true,
writable: true
});
switch (new URL(document.URL).hostname) {
case "www.cqmetro.cn":
CRT.bootstrap();
break;
case "www.wuhanrt.com":
WHRT.bootstrap();
break;
}
})();