scrapbox2slack
code:main.gs(js)
const global=this;
function subscribe(settings) {
}
(() => {
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : objkey = value; var __spreadValues = (a2, b2) => {
for (var prop in b2 || (b2 = {}))
if (__hasOwnProp.call(b2, prop))
__defNormalProp(a2, prop, b2prop); if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b2)) {
if (__propIsEnum.call(b2, prop))
__defNormalProp(a2, prop, b2prop); }
return a2;
};
var __spreadProps = (a2, b2) => __defProps(a2, __getOwnPropDescs(b2));
var __objRest = (source, exclude) => {
var target = {};
for (var prop in source)
if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
if (source != null && __getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(source)) {
if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
}
return target;
};
const postToSlack = (params) => {
const temp = [];
for (const _a of params) {
const _b = _a, { blocks: blocks1 } = _b, rest = __objRest(_b, "blocks"); if (blocks1.length > 50) {
temp.push(__spreadValues({
blocks: blocks1.slice(0, 50 - 1)
}, rest), __spreadValues({
blocks: blocks1.slice(50 - 1)
}, rest));
}
temp.push(__spreadValues({
blocks: blocks1
}, rest));
}
const count = Math.floor(temp.length / 100) + 1;
for (let i = 0; i < count; i++) {
try {
UrlFetchApp.fetchAll(temp.slice(i * 100, (i + 1) * 100).map(({ url, blocks, description }) => ({
url,
method: "post",
headers: {
"Content-Type": "application/json"
},
payload: JSON.stringify({
text: description,
blocks
})
})));
} catch (e) {
console.error(e);
}
}
};
var b = (e) => ({
type: "title",
});
var y = (e) => {
let { rows: t, ...o } = e, { indent: r = 0, text: n = "" } = t != null ? t : {}, c = n.replace(/^\s*code:/, ""); return {
indent: r,
type: "codeBlock",
fileName: c,
content: o.map((i) => i.text.substring(r + 1)).join(`
`)
};
};
var s = (e, { parseOnNested: t, parseOnQuoted: o, patterns: r }) => (n, c, i) => {
var p, l, m, u, f, N;
if (!t && c.nested)
return (p = i == null ? void 0 : i()) !== null && p !== void 0 ? p : [];
if (!o && c.quoted)
return (l = i == null ? void 0 : i()) !== null && l !== void 0 ? l : [];
for (let D of r) {
let g = D.exec(n);
if (g === null)
continue;
let Z = n.substring(0, g.index), A = n.substring(g.index + ((u = (m = g0) === null || m === void 0 ? void 0 : m.length) !== null && u !== void 0 ? u : 0)), J = e((f = g0) !== null && f !== void 0 ? f : "", c); return [
...d(Z, c),
...J,
...d(A, c)
];
}
return (N = i == null ? void 0 : i()) !== null && N !== void 0 ? N : [];
};
var a = (e) => [
{
type: "plain",
raw: e,
text: e
}
], T = s(a, {
parseOnNested: true,
parseOnQuoted: true,
patterns: [
/^()(.*)()$/
]
});
var K = /^>.*$/, V = (e, t) => t.context === "table" ? a(e, t) : [
{
type: "quote",
raw: e,
nodes: d(e.substring(1), __spreadProps(__spreadValues({}, t), {
quoted: true
}))
}
], O = s(V, {
parseOnNested: false,
parseOnQuoted: false,
patterns: [
K
]
});
var X = /^\? .+$/, Y = (e, t) => t.context === "table" ? a(e, t) : [
{
type: "helpfeel",
raw: e,
text: e.substring(2)
}
], I = s(Y, {
parseOnNested: false,
parseOnQuoted: false,
patterns: [
X
]
});
var w = /\[\[https?:\/\/^\s\]+\.(?:png|jpe?g|gif|svg)\]\]/i, ee = /\[\[https?:\/\/(?:0-9a-z-+\.)?gyazo\.com\/0-9a-f{32}\]\]/, te = (e, t) => { if (t.context === "table")
return a(e, t);
let o = e.substring(2, e.length - 2), r = /^https?:\/\/(0-9a-z-\.)?gyazo\.com\/0-9a-f{32}$/.test(o); return [
{
type: "strongImage",
raw: e,
src: r ? ${o}/thumb/1000 : o
}
];
}, R = s(te, {
parseOnNested: false,
parseOnQuoted: true,
patterns: [
w,
ee
]
});
var oe = /\^[\*\.icon(?:\*1-9\d*)?\]/; function h(e) {
return (t, o) => {
if (e === "strongIcon" && o.context === "table")
return a(t, o);
let r = e === "icon" ? t.substring(1, t.length - 1) : t.substring(2, t.length - 2), n = r.lastIndexOf(".icon"), c = r.substring(0, n), i = c.startsWith("/") ? "root" : "relative", p = r.substring(n + 5, r.length), l = p.startsWith("*") ? parseInt(p.substring(1), 10) : 1;
return new Array(l).fill({}).map(() => ({
path: c,
pathType: i,
type: e,
raw: t
}));
};
}
var re = h("icon"), E = s(re, {
parseOnNested: false,
parseOnQuoted: true,
patterns: [
oe
]
});
var ne = /\[\^[\*\.icon(?:\*\d+)?\]\]/, se = h("strongIcon"), k = s(se, {
parseOnNested: false,
parseOnQuoted: true,
patterns: [
ne
]
});
var ae = /\[\[(?:[^[]|\[[^[]).*?\]*\]\]/, ce = (e, t) => t.context === "table" ? a(e, t) : [
{
type: "strong",
raw: e,
nodes: d(e.substring(2, e.length - 2), __spreadProps(__spreadValues({}, t), {
nested: true
}))
}
], $ = s(ce, {
parseOnNested: false,
parseOnQuoted: true,
patterns: [
ae
]
});
var ie = /\\$ .+? \/, de = /\[\$ ^\]+\]/, pe = (e, t) => t.context === "table" ? a(e, t) : [ {
type: "formula",
raw: e,
formula: e.substring(3, e.length - (e.endsWith(" ]") ? 2 : 1))
}
], S = s(pe, {
parseOnNested: false,
parseOnQuoted: true,
patterns: [
ie,
de
]
});
var le = /\!"#%&'()*+,\-./{|}<>_~]+ (?:\[[^[\+\]|^\])+\]/, me = (e, t) => { if (t.context === "table")
return a(e, t);
let o = e.indexOf(" "), r = e.substring(1, o), n = e.substring(o + 1, e.length - 1), c = new Set(r);
if (c.has("*")) {
let i = r.split("*").length - 1;
c.delete("*"), c.add(*-${Math.min(i, 10)});
}
return [
{
type: "decoration",
raw: e,
rawDecos: r,
decos: Array.from(c),
nodes: d(n, __spreadProps(__spreadValues({}, t), {
nested: true
}))
}
];
}, z = s(me, {
parseOnNested: false,
parseOnQuoted: true,
patterns: [
le
]
});
var ue = /.*?/, ge = (e, t) => t.context === "table" ? a(e, t) : [
{
type: "code",
raw: e,
text: e.substring(1, e.length - 1)
}
], Q = s(ge, {
parseOnNested: false,
parseOnQuoted: true,
patterns: [
ue
]
});
var fe = /^$% .+$/, Ne = (e, t) => { var o;
if (t.context === "table")
return a(e, t);
let r = (o = e0) !== null && o !== void 0 ? o : "", n = e.substring(2); return [
{
type: "commandLine",
raw: e,
symbol: r,
text: n
}
];
}, _ = s(Ne, {
parseOnNested: false,
parseOnQuoted: false,
patterns: [
fe
]
});
var he = /\\s+\/, xe = (e, t) => t.context === "table" ? a(e, t) : [ {
type: "blank",
raw: e,
text: e.substring(1, e.length - 1)
}
], F = s(xe, {
parseOnNested: false,
parseOnQuoted: true,
patterns: [
he
]
});
var ve = /\[https?:\/\/^\s\]+\.(?:png|jpe?g|gif|svg)(?:\?^\\s]+)?(?:\s+https?:\/\/^\s\]+)?\]/i, Pe = /\[https?:\/\/^\s\]+\s+https?:\/\/^\s\]+\.(?:png|jpe?g|gif|svg)(?:\?^\\s]+)?\]/i, be = /\[https?:\/\/(?:0-9a-z-+\.)?gyazo\.com\/0-9a-f{32}(?:\/raw)?(?:\s+https?:\/\/^\s\]+)?\]/, ye = /\[https?:\/\/^\s\]+\s+https?:\/\/(?:0-9a-z-+\.)?gyazo\.com\/0-9a-f{32}(?:\/raw)?\]/, Te = (e) => /^https?:\/\/^\s\]+\.(png|jpe?g|gif|svg)(\?^\\s]+)?$/i.test(e) || Oe(e), Oe = (e) => /^https?:\/\/(0-9a-z-\.)?gyazo\.com\/0-9a-f{32}(\/raw)?$/.test(e), Ie = (e, t) => { if (t.context === "table")
return a(e, t);
let o = e.search(/\s/), r = o !== -1 ? e.substring(1, o) : e.substring(1, e.length - 1), n = o !== -1 ? e.substring(o, e.length - 1).trimLeft() : "", c, i = Te(n) ? [ n,
r
] : [
r,
n
];
return [
{
type: "image",
raw: e,
src: /^https?:\/\/(0-9a-z-\.)?gyazo\.com\/0-9a-f{32}$/.test(c) ? ${c}/thumb/1000 : c, link: i
}
];
}, C = s(Ie, {
parseOnNested: true,
parseOnQuoted: true,
patterns: [
ve,
Pe,
be,
ye
]
});
var Re = /\[https?:\/\/^\s\]+\s+^\]*^\s\]/, Ee = /\^[\*^\s\s+https?:\/\/^\s\]+\]/, ke = /\[https?:\/\/^\s\]+\]/, $e = /https?:\/\/^\s+/, Se = (e, t) => { if (t.context === "table")
return a(e, t);
let o = e.startsWith("&& e.endsWith("") ? e.substring(1, e.length - 1) : e, r = /^https?:\/\/^\s\]/.test(o), n = (r ? /^https?:\/\/^\s\]+/ : /https?:\/\/^\s\]+$/).exec(o); if ((n == null ? void 0 : n0) === void 0) return [];
let c = r ? o.substring(n0.length) : o.substring(0, n.index - 1); return [
{
type: "link",
raw: e,
pathType: "absolute",
content: c.trim()
}
];
}, L = s(Se, {
parseOnNested: true,
parseOnQuoted: true,
patterns: [
Re,
Ee,
ke,
$e
]
});
var W = /\[(^\]*^\s)\s+(NS\d+(?:\.\d+)?,EW\d+(?:\.\d+)?(?:,Z\d+)?)\]/, B = /\[(NS\d+(?:\.\d+)?,EW\d+(?:\.\d+)?(?:,Z\d+)?)(?:\s+(^\]*^\s))?\]/, ze = (e) => { let t = "", o = "", r = "" = e.split(","), n = parseFloat(t.replace(/^N/, "").replace(/^S/, "-")), c = parseFloat(o.replace(/^E/, "").replace(/^W/, "-")), i = /^Z\d+$/.test(r) ? parseInt(r.replace(/^Z/, ""), 10) : 14; return {
latitude: n,
longitude: c,
zoom: i
};
}, Qe = (e, t) => {
var o;
if (t.context === "table")
return a(e, t);
let r = (o = e.match(W)) !== null && o !== void 0 ? o : e.match(B);
if (r === null)
return [];
let n = e.startsWith("[N") || e.startsWith("[S"), c = "", i = "" = n ? r : [
], { latitude: p, longitude: l, zoom: m } = ze(c), u = i !== "" ? https://www.google.com/maps/place/${encodeURIComponent(i)}/@${p},${l},${m}z : https://www.google.com/maps/@${p},${l},${m}z;
return [
{
type: "googleMap",
raw: e,
latitude: p,
longitude: l,
zoom: m,
place: i,
url: u
}
];
}, G = s(Qe, {
parseOnNested: false,
parseOnQuoted: true,
patterns: [
W,
B
]
});
var _e = /\[\/?[^\]+\]/, Fe = (e) => { let t = e.substring(1, e.length - 1);
return [
{
type: "link",
raw: e,
pathType: t.startsWith("/") ? "root" : "relative",
href: t,
content: ""
}
];
}, H = s(Fe, {
parseOnNested: true,
parseOnQuoted: true,
patterns: [
_e
]
});
var Ce = /(?:^|\s)#\S+/, Le = (e, t) => {
if (t.context === "table")
return a(e, t);
if (e.startsWith("#"))
return [
{
type: "hashTag",
raw: e,
href: e.substring(1)
}
];
let o = e.substring(0, 1), r = e.substring(1);
return [
...a(o, t),
{
type: "hashTag",
raw: r,
href: r.substring(1)
}
];
}, M = s(Le, {
parseOnNested: true,
parseOnQuoted: true,
patterns: [
Ce
]
});
var We = (e, t, o) => {
var r;
return e === "" ? [] : (r = o == null ? void 0 : o()) !== null && r !== void 0 ? r : [];
}, Be = (...e) => (t, o) => e.reduceRight((r, n) => () => n(t, o, r), () => T(t, o))(), d = Be(We, O, I, Q, _, S, F, z, R, k, $, C, L, E, G, H, M);
var U = (e) => {
let { rows: t, ...o } = e, { indent: r = 0, text: n = "" } = t != null ? t : {}, c = n.replace(/^\s*table:/, ""); return {
indent: r,
type: "table",
fileName: c,
cells: o.map((i) => i.text.substring(r + 1)).map((i) => i.split(" ").map((p) => d(p, {
nested: false,
quoted: false,
context: "table"
})))
};
};
var q = (e) => {
let { indent: t, text: o } = e.rows0; return {
indent: t,
type: "line",
nodes: d(o.substring(t), {
nested: false,
quoted: false,
context: "line"
})
};
};
var x = (e) => {
switch (e.type) {
case "title":
return b(e);
case "codeBlock":
return y(e);
case "table":
return U(e);
case "line":
return q(e);
}
};
var v = (e) => e.split(`
`).map((t) => {
var o, r, n;
return {
indent: (n = (r = (o = /^\s+/.exec(t)) === null || o === void 0 ? void 0 : o0) === null || r === void 0 ? void 0 : r.length) !== null && n !== void 0 ? n : 0, text: t
};
});
var Ge = (e, t) => {
var o, r;
return (e.type === "codeBlock" || e.type === "table") && t.indent > ((r = (o = e.rows0) === null || o === void 0 ? void 0 : o.indent) !== null && r !== void 0 ? r : 0); }, j = (e, t) => {
return o !== void 0 && Ge(o, t) ? (o.rows.push(t), e) : (e.push({
type: /^\s*code:/.test(t.text) ? "codeBlock" : /^\s*table:/.test(t.text) ? "table" : "line",
rows: [
t
]
}), e);
}, P = (e, t) => {
var o;
if ((o = t.hasTitle) !== null && o !== void 0 ? o : true) {
return r === void 0 ? [] : [
{
type: "title",
rows: [
r
]
},
...n.reduce(j, [])
];
}
return e.reduce(j, []);
};
var He = (e, t) => {
var o;
let r = v(e);
return P(r, {
hasTitle: (o = t == null ? void 0 : t.hasTitle) !== null && o !== void 0 ? o : true
}).map(x);
};
const sb2mrkdwn = (text, project) => {
const blocks = He(text, {
hasTitle: false
});
return blocks.flatMap((block) => {
const data = convertSb2Md(block, project);
return data ? [
data
] : [];
});
};
const convertSb2Md = (block, project) => {
switch (block.type) {
case "title":
return;
case "codeBlock":
return {
type: "section",
text: {
type: "mrkdwn",
text: \`${block.fileName}\
\\`\`${block.content}\`\`\`
}
};
case "table":
return {
type: "section",
text: {
type: "mrkdwn",
text: \`table:${block.fileName}\`
}
};
case "line":
return convertLine(block, project);
}
};
const convertLine = (line, project) => {
const objects = line.nodes.flatMap((node) => convertNode(node, project));
if (objects.length === 1 && objects0 && objects0.type === "image" && !/^https:\/\/scrapbox\.io\/api\/pages\/.+\/.+\/icon$/.test(objects0.image_url)) { }
const elements = line.indent > 0 ? [
{
type: "plain_text",
text: ${"\u3000".repeat(line.indent - 1)}\u25CF
}
] : [];
let chunk;
for (const object of objects) {
if (object.type !== "mrkdwn") {
if (chunk)
elements.push(chunk);
chunk = void 0;
elements.push(object);
continue;
}
chunk = {
type: "mrkdwn",
text: ${chunk ? chunk.text : ""}${object.text}
};
}
if (chunk)
elements.push(chunk);
if (elements.length === 0) {
elements.push({
type: "plain_text",
text: " "
});
}
return {
type: "context",
elements
};
};
const convertNode = (node1, project) => {
switch (node1.type) {
case "quote": {
const objects = node1.nodes.flatMap((node) => convertNode(node, project));
if (objects.length === 0)
objects.push({
type: "plain_text",
text: " "
});
case "plain_text":
case "mrkdwn":
return [
{
type: "mrkdwn",
text: >${objects[0].text}
},
...objects.slice(1)
];
default:
break;
}
return objects;
}
case "image":
case "strongImage":
return [
{
type: "image",
image_url: node1.src,
alt_text: "image"
}
];
case "icon":
case "strongIcon": {
const path = node1.pathType === "relative" ? /${project}/${node1.path} : node1.path;
return [
{
type: "image",
image_url: https://scrapbox.io/api/pages${path}/icon,
alt_text: node1.path
}
];
}
case "formula":
return [
{
type: "mrkdwn",
text: \`${node1.formula}\`
}
];
case "helpfeel":
return [
{
type: "mrkdwn",
text: \`? ${node1.text}\`
}
];
case "commandLine":
return [
{
type: "mrkdwn",
text: \`${node1.symbol} ${node1.text}\`
}
];
case "code":
return [
{
type: "mrkdwn",
text: \`${node1.text}\`
}
];
case "decoration": {
const hasStrong = node1.decos.some((deco) => /\*-/.test(deco0)); const hasItalic = node1.decos.includes("/");
const hasStrike = node1.decos.includes("-");
return node1.nodes.flatMap((node) => convertNode(node, project)).map((object) => {
if (object.type !== "plain_text" || !/^\s*$/.test(object.text) || !/^<https?:\/\/.+\|.+>$/.test(object.text)) {
return object;
}
let text = object.text;
if (hasStrong)
text = *${text}*;
if (hasItalic)
text = _${text}_;
if (hasStrike)
text = ~${text}~;
return {
type: "mrkdwn",
text: ${text}
};
});
}
case "strong":
return node1.nodes.flatMap((node) => convertNode(node, project)).map((object) => {
if (object.type !== "plain_text" || !/^\s*$/.test(object.text) || !/^<https?:\/\/.+\|.+>$/.test(object.text)) {
return object;
}
return {
type: "mrkdwn",
text: *${object.text}*
};
});
case "googleMap":
return [
{
type: "mrkdwn",
text: <${node1.url}|${node1.place}>
}
];
case "link": {
switch (node1.pathType) {
case "root":
return [
{
type: "mrkdwn",
text: <https://scrapbox.io${node1.href}|${node1.href}>
}
];
case "relative":
return [
{
type: "mrkdwn",
text: <https://scrapbox.io/${project}/${node1.href}|${node1.href}>
}
];
case "absolute":
break;
}
return [
{
type: "mrkdwn",
text: <${node1.href}|${node1.content || node1.href}>
}
];
}
case "hashTag":
return [
{
type: "mrkdwn",
text: <https://scrapbox.io/${project}/${node1.href}|#${node1.href}>
}
];
case "blank":
case "plain":
return [
{
type: "mrkdwn",
text: node1.text
}
];
}
};
const toBlocks = (project, title, lineBlocks) => {
const id = lineBlocks.length > 0 ? lineBlocks00.id : void 0; return [
{
type: "section",
text: {
type: "mrkdwn",
text: *<https://scrapbox.io/${project}/${encodeURIComponent(title)}${id !== void 0 ? #${id} : ""}|${title}>* }
},
...lineBlocks.flatMap((lines) => [
...sb2mrkdwn(lines.map((line) => line.text).join("\n"), project),
{
type: "divider"
}
])
];
};
function requiredArgs(required, args) {
if (args.length < required) {
throw new TypeError(required + " argument" + (required > 1 ? "s" : "") + " required, but only " + args.length + " present");
}
}
function toDate(argument) {
requiredArgs(1, arguments);
const argStr = Object.prototype.toString.call(argument);
if (argument instanceof Date || typeof argument === "object" && argStr === "object Date") { return new Date(argument.getTime());
} else if (typeof argument === "number" || argStr === "object Number") { return new Date(argument);
} else {
if ((typeof argument === "string" || argStr === "object String") && typeof console !== "undefined") { console.warn("Starting with v2.0.0-beta.1 date-fns doesn't accept strings as date arguments. Please use parseISO to parse strings. See: https://git.io/fjule"); console.warn(new Error().stack);
}
return new Date(NaN);
}
}
function addLeadingZeros(number, targetLength) {
var sign = number < 0 ? "-" : "";
var output = Math.abs(number).toString();
while (output.length < targetLength) {
output = "0" + output;
}
return sign + output;
}
const formatters = {
y(date, token) {
const signedYear = date.getUTCFullYear();
const year = signedYear > 0 ? signedYear : 1 - signedYear;
return addLeadingZeros(token === "yy" ? year % 100 : year, token.length);
},
M(date, token) {
const month = date.getUTCMonth();
return token === "M" ? String(month + 1) : addLeadingZeros(month + 1, 2);
},
d(date, token) {
return addLeadingZeros(date.getUTCDate(), token.length);
},
a(date, token) {
const dayPeriodEnumValue = date.getUTCHours() / 12 >= 1 ? "pm" : "am";
switch (token) {
case "a":
case "aa":
return dayPeriodEnumValue.toUpperCase();
case "aaa":
return dayPeriodEnumValue;
case "aaaaa":
return dayPeriodEnumValue0; case "aaaa":
default:
return dayPeriodEnumValue === "am" ? "a.m." : "p.m.";
}
},
h(date, token) {
return addLeadingZeros(date.getUTCHours() % 12 || 12, token.length);
},
H(date, token) {
return addLeadingZeros(date.getUTCHours(), token.length);
},
m(date, token) {
return addLeadingZeros(date.getUTCMinutes(), token.length);
},
s(date, token) {
return addLeadingZeros(date.getUTCSeconds(), token.length);
},
S(date, token) {
const numberOfDigits = token.length;
const milliseconds = date.getUTCMilliseconds();
const fractionalSeconds = Math.floor(milliseconds * Math.pow(10, numberOfDigits - 3));
return addLeadingZeros(fractionalSeconds, token.length);
}
};
function getTimezoneOffsetInMilliseconds(date) {
const utcDate = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds()));
utcDate.setUTCFullYear(date.getFullYear());
return date.getTime() - utcDate.getTime();
}
function isValid(dirtyDate) {
requiredArgs(1, arguments);
var date = toDate(dirtyDate);
return !isNaN(date);
}
function toInteger(dirtyNumber) {
if (dirtyNumber === null || dirtyNumber === true || dirtyNumber === false) {
return NaN;
}
const number = Number(dirtyNumber);
if (isNaN(number)) {
return number;
}
return number < 0 ? Math.ceil(number) : Math.floor(number);
}
function addMilliseconds(dirtyDate, dirtyAmount) {
requiredArgs(2, arguments);
const timestamp = toDate(dirtyDate).getTime();
const amount = toInteger(dirtyAmount);
return new Date(timestamp + amount);
}
function subMilliseconds(dirtyDate, dirtyAmount) {
requiredArgs(2, arguments);
const amount = toInteger(dirtyAmount);
return addMilliseconds(dirtyDate, -amount);
}
const formattingTokensRegExp = /(\w)\1*|''|'(''|^')+('|$)|./g; const escapedStringRegExp = /^'(^*?)'?$/; const doubleQuoteRegExp = /''/g;
const unescapedLatinCharacterRegExp = /a-zA-Z/; function lightFormat(dirtyDate, formatStr) {
requiredArgs(2, arguments);
const originalDate = toDate(dirtyDate);
if (!isValid(originalDate)) {
throw new RangeError("Invalid time value");
}
const timezoneOffset = getTimezoneOffsetInMilliseconds(originalDate);
const utcDate = subMilliseconds(originalDate, timezoneOffset);
const tokens = formatStr.match(formattingTokensRegExp);
if (!tokens)
return "";
const result = tokens.map((substring) => {
if (substring === "''") {
return "'";
}
const firstCharacter = substring0; if (firstCharacter === "'") {
return cleanEscapedString(substring);
}
if (formatter) {
return formatter(utcDate, substring);
}
if (firstCharacter.match(unescapedLatinCharacterRegExp)) {
throw new RangeError("Format string contains an unescaped latin alphabet character " + firstCharacter + "");
}
return substring;
}).join("");
return result;
}
function cleanEscapedString(input) {
const matches = input.match(escapedStringRegExp);
if (!matches) {
return input;
}
return matches1.replace(doubleQuoteRegExp, "'"); }
function* getPages(pages, { sid }) {
console.log([getPages()] Start fetching ${pages.length} scrapbox pages...);
const count = Math.floor(pages.length / 10) + 1;
for (let i = 0; i < count; i++) {
console.log([getPages()] ${i * 10}/${pages.length});
const responses = UrlFetchApp.fetchAll(pages.slice(i * 10, (i + 1) * 10).map(({ project, title }) => ({
url: https://scrapbox.io/api/pages/${project}/${encodeURIComponent(title)},
headers: {
Cookie: connect.sid=${sid}
},
muteHttpExceptions: true
})));
const pages_ = pages.slice(i * 10, (i + 1) * 10);
const jsons = responses.map((response, j1) => __spreadProps(__spreadValues({}, JSON.parse(response.getContentText())), {
project: pages_j1.project, }));
yield jsons;
}
}
function* getModifiedTitles(projects, { from, sid }) {
console.log(Start searching ${projects.length} scrapbox projects for pages which are updated from ${lightFormat(from, "yyyy-MM-dd HH:mm:ss")}: , projects);
for (const project of projects) {
const data = getList(project, {
sid,
skip: 0
});
if ("name" in data) {
console.error(Error at "/${project}": ${data.name} ${data.message});
continue;
}
const updates = [];
for (const page of data.pages) {
if (page.updated <= from.getTime() / 1e3)
continue;
updates.push(page.updated);
yield {
project,
title: page.title,
updated: page.updated
};
}
if (updates.length < 2)
continue;
console.log({
project,
from: lightFormat(new Date(updates.length > 0 ? Math.min(...updates) * 1e3 : from.getTime()), "yyyy-MM-dd HH:mm:ss")
});
}
console.log(Finish fetching.);
}
const getList = (project, { sid, skip }) => {
const response = UrlFetchApp.fetch(https://scrapbox.io/api/pages/${project}?limit=1000&skip=${skip}, {
headers: {
Cookie: connect.sid=${sid}
},
muteHttpExceptions: true
});
return JSON.parse(response.getContentText());
};
global.subscribe = (settings) => {
const lastUpdated = getUpdated();
const sid = getSid();
if (sid === null) {
throw Error("Please set cookie.sid");
}
const updatedTitleList = [
...getModifiedTitles([
...new Set(settings.map(({ project }) => project))
], {
from: lastUpdated,
sid
})
];
setUpdated(Math.max(...updatedTitleList.map(({ updated }) => updated), lastUpdated.getTime() / 1e3));
console.log(Fetch updates until ${lightFormat(getUpdated(), "yyyy-MM-dd HH:mm:ss")});
for (const jsons of getPages(updatedTitleList, {
sid
})) {
const pageDataList = jsons.flatMap((json) => {
if ("name" in json) {
console.error(`Failed to fetch "/${json.project}/${json.title}"
name: ${json.name}
message: ${json.message}`);
return [];
}
return [
{
project: json.project,
title: json.title,
lineBlocks: getModifiedLines(json.lines, lastUpdated.getTime() / 1e3)
}
];
});
const params = settings.flatMap(({ webhook, project, include, exclude }) => pageDataList.flatMap(({ project: project_, title, lineBlocks }) => {
if (project_ !== project)
return [];
const lines = lineBlocks.flat();
if (include && !lines.some(({ text }) => include.test(text)))
return [];
if (exclude && lines.some(({ text }) => exclude.test(text)))
return [];
return [
{
url: webhook,
blocks: toBlocks(project, title, lineBlocks),
description: lines.slice(0, 5).map((line) => line.text).join("\n")
}
];
}));
postToSlack(params);
}
};
const getModifiedLines = (lines, from) => {
const result = [];
let chunk = [];
for (const line of lines) {
if (line.updated <= from) {
if (chunk.length === 0)
continue;
result.push([
...chunk
]);
chunk = [];
continue;
}
chunk.push(line);
}
if (chunk.length > 0)
result.push([
...chunk
]);
return result;
};
const getUpdated = () => {
var _a;
const scriptProperties = PropertiesService.getScriptProperties();
const value = parseFloat((_a = scriptProperties.getProperty("LAST_UPDATED")) != null ? _a : "0");
return !isNaN(value) ? new Date(value * 1e3) : yesterday();
};
const setUpdated = (...times) => {
const scriptProperties = PropertiesService.getScriptProperties();
scriptProperties.setProperty("LAST_UPDATED", ${Math.max(...times)});
};
const getSid = () => {
const scriptProperties = PropertiesService.getScriptProperties();
return scriptProperties.getProperty("CONNECT_SID");
};
const yesterday = () => {
const now = new Date();
now.setDate(now.getDate() - 1);
return now;
};
})();
function main(){
subscribe(createDefaultSettings())
}