Files
jrshikoku/scripts/generate-operation-info-userscript.mjs
harukin-expo-dev-env 4dd0775640 feat: add userscript generator for JR Shikoku operation info
- Implemented a script to generate a Tampermonkey userscript from ndView.tsx.
- Extracted and modified the operation page script body to include necessary postMessage functions.
- Added metadata for the userscript including name, namespace, version, and match URL.
- Ensured compatibility with Tampermonkey's GM_download for image capture.
2026-06-20 06:07:39 +00:00

102 lines
3.5 KiB
JavaScript

import fs from "node:fs";
import path from "node:path";
import { fileURLToPath } from "node:url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const repoRoot = path.resolve(__dirname, "..");
const sourcePath = path.join(repoRoot, "ndView.tsx");
const outputDir = path.join(repoRoot, "docs", "generated");
const outputPath = path.join(outputDir, "jrshikoku-operation-info.user.js");
const source = fs.readFileSync(sourcePath, "utf8");
const match = source.match(/return String\.raw`([\s\S]*?)`;\n};/);
if (!match) {
throw new Error("Failed to locate buildOperationPageScript body in ndView.tsx");
}
let scriptBody = match[1];
scriptBody = scriptBody.replace(
" window.__jrsNativeOperationLayout = ${nativeLayout};",
[
" window.__jrsNativeOperationLayout = Object.assign({",
" forceSignage: true,",
" safeAreaLeft: 0,",
" safeAreaRight: 0,",
" lineBadges: []",
" }, window.__TM_OPERATION_INFO_LAYOUT || {});"
].join("\n")
);
const nativePostMessageBlock = [
" function postMessage(payload) {",
" if (!window.ReactNativeWebView) return;",
" payload.type = 'operationInfoCapture';",
" window.ReactNativeWebView.postMessage(JSON.stringify(payload));",
" }"
].join("\n");
const tampermonkeyPostMessageBlock = [
" function downloadCapture(dataUrl, fileName) {",
" if (!dataUrl) return;",
" if (typeof GM_download === 'function') {",
" try {",
" GM_download({ url: dataUrl, name: fileName, saveAs: true });",
" return;",
" } catch (error) {",
" console.warn('[JRShikoku TM] GM_download failed, falling back to anchor download.', error);",
" }",
" }",
"",
" var link = document.createElement('a');",
" link.href = dataUrl;",
" link.download = fileName || ('operation-info-' + Date.now() + '.png');",
" link.rel = 'noopener';",
" document.body.appendChild(link);",
" link.click();",
" link.remove();",
" }",
"",
" function postMessage(payload) {",
" if (!payload) return;",
" if (payload.error) {",
" console.error('[JRShikoku TM] capture failed', payload);",
" window.alert('運行情報の画像生成に失敗しました。');",
" return;",
" }",
" downloadCapture(payload.dataUrl, payload.fileName);",
" }"
].join("\n");
if (!scriptBody.includes(nativePostMessageBlock)) {
throw new Error("Failed to locate React Native postMessage block in ndView.tsx");
}
scriptBody = scriptBody.replace(nativePostMessageBlock, tampermonkeyPostMessageBlock);
const header = [
"// ==UserScript==",
"// @name JR四国 運行情報 Inject",
"// @namespace https://github.com/harukin/jrshikoku",
"// @version 0.1.0",
"// @description Run the JR Shikoku operation-info injection on desktop browsers via Tampermonkey.",
"// @match https://www.jr-shikoku.co.jp/info/*",
"// @run-at document-idle",
"// @grant GM_download",
"// ==/UserScript==",
"",
"/* Generated from ndView.tsx by scripts/generate-operation-info-userscript.mjs. */",
"",
"window.__TM_OPERATION_INFO_LAYOUT = Object.assign({",
" forceSignage: true,",
" safeAreaLeft: 0,",
" safeAreaRight: 0,",
" lineBadges: []",
"}, window.__TM_OPERATION_INFO_LAYOUT || {});",
""
].join("\n");
fs.mkdirSync(outputDir, { recursive: true });
fs.writeFileSync(outputPath, header + scriptBody.trimStart() + "\n", "utf8");
console.log(path.relative(repoRoot, outputPath));