Обновить t1.js

This commit is contained in:
z244300 2025-08-14 05:49:36 +00:00
parent 5158e84272
commit 6a9cec78be

203
t1.js
View File

@ -1 +1,202 @@
let test = "string";
// t1.js — удалённый скрипт для Scriptable Remote Loader
// Сканирование штрихкодов/QR по фото + история
async function __main(ctx) { // точка входа для бутлоадера
const menu = new Alert();
menu.title = "Сканер (фото) + история";
menu.addAction("Сканировать");
menu.addAction("История");
menu.addDestructiveAction("Очистить историю");
menu.addCancelAction("Отмена");
const c = await menu.presentSheet();
if (c === 0) return scanFromCamera(ctx);
if (c === 1) return showHistory();
if (c === 2) return clearHistory();
}
// --- Настройки/хранилище ---
const FILE_NAME = "scriptable_scans.json";
const USE_ICLOUD = false;
const fm = USE_ICLOUD ? FileManager.iCloud() : FileManager.local();
const storePath = fm.joinPath(fm.documentsDirectory(), FILE_NAME);
function loadHistory() {
try {
if (!fm.fileExists(storePath)) return [];
return JSON.parse(fm.readString(storePath)) || [];
} catch (e) { console.error(e); return []; }
}
function saveHistory(arr) {
try { fm.writeString(storePath, JSON.stringify(arr, null, 2)); }
catch (e) { console.error(e); }
}
// --- Основные функции ---
async function scanFromCamera(ctx) {
try {
const img = await Photos.fromCamera(); // системный запрос на доступ к камере тут
const base64 = Data.fromJPEG(img).toBase64String(); // JPEG — лучше для 1D
const wv = new WebView();
wv.shouldAllowRequest = req => {
const u = req.url || "";
if (u.startsWith("scriptable://decoded")) {
const q = parseQS(u);
const text = q.text || "";
const format = q.format || "UNKNOWN";
if (text) {
const h = loadHistory();
h.unshift({ text, format, ts: new Date().toISOString() });
saveHistory(h);
notify(ctx, "Сохранено", `${format}: ${text}`);
} else {
notify(ctx, "Не найдено", "Код распознать не удалось");
}
return false; // не покидать WebView
}
return true;
};
await wv.loadHTML(decoderHTML(base64));
await wv.present(true);
} catch (e) {
console.error(e);
await notify(ctx, "Ошибка", String(e));
}
}
async function showHistory() {
const history = loadHistory();
const table = new UITable();
table.showSeparators = true;
const hdr = new UITableRow();
const c = hdr.addText("История", `${history.length} записей`);
c.titleFont = Font.boldSystemFont(16);
c.subtitleFont = Font.systemFont(12);
table.addRow(hdr);
if (!history.length) {
const r = new UITableRow();
r.addText("Пусто", "Сканируйте код через «Сканировать».");
table.addRow(r);
await table.present(); return;
}
for (const it of history) {
const r = new UITableRow();
r.onSelect = async () => { Pasteboard.copy(it.text); await notify(null, "Скопировано", it.text); };
r.addText(it.text, `${it.format || "CODE"} · ${new Date(it.ts).toLocaleString()}`);
table.addRow(r);
}
await table.present();
}
async function clearHistory() {
const x = new Alert();
x.title = "Очистить историю?";
x.addDestructiveAction("Очистить");
x.addCancelAction("Отмена");
if (await x.presentAlert() === 0) {
saveHistory([]);
await notify(null, "Готово", "История очищена");
}
}
// --- Вспомогательные ---
function parseQS(url) {
const out = {}; const i = url.indexOf("?"); if (i < 0) return out;
for (const p of url.slice(i + 1).split("&")) {
const [k, v] = p.split("=");
out[decodeURIComponent(k || "")] = decodeURIComponent(v || "");
}
return out;
}
async function notify(ctx, title, body) {
try {
if (ctx && typeof ctx.notify === "function") return ctx.notify(title, body);
const n = new Notification(); n.title = title; n.body = body; await n.schedule();
} catch (e) {}
}
// --- HTML с ZXing: распознаём 1D + QR, несколько попыток и повороты ---
function decoderHTML(b64) {
return `<!doctype html><meta name="viewport" content="width=device-width,initial-scale=1">
<title>Decode</title>
<style>
body{margin:0;background:#111;color:#eee;font-family:-apple-system,system-ui}
main{padding:16px}
pre{white-space:pre-wrap}
canvas{max-width:100%;display:block;border:1px solid #333}
</style>
<main>
<p>Распознаю штрихкод</p>
<canvas id="cv"></canvas>
<pre id="out"></pre>
</main>
<script src="https://unpkg.com/@zxing/library@latest"></script>
<script>
(async () => {
const img = new Image(); img.src = "data:image/jpeg;base64,${b64}";
await new Promise(r => img.onload = r);
const cv = document.getElementById('cv');
const ctx = cv.getContext('2d');
// Масштабируем до разумного предела
const maxSide = 1920;
let w = img.naturalWidth, h = img.naturalHeight;
const k = Math.max(w,h) > maxSide ? maxSide/Math.max(w,h) : 1;
w = Math.round(w*k); h = Math.round(h*k);
cv.width = w; cv.height = h; ctx.drawImage(img,0,0,w,h);
const formats = [
ZXing.BarcodeFormat.EAN_13, ZXing.BarcodeFormat.EAN_8,
ZXing.BarcodeFormat.UPC_A, ZXing.BarcodeFormat.UPC_E,
ZXing.BarcodeFormat.CODE_128, ZXing.BarcodeFormat.CODE_39,
ZXing.BarcodeFormat.ITF, ZXing.BarcodeFormat.CODABAR,
ZXing.BarcodeFormat.QR_CODE
];
const hints = new Map();
hints.set(ZXing.DecodeHintType.POSSIBLE_FORMATS, formats);
hints.set(ZXing.DecodeHintType.TRY_HARDER, true);
const reader = new ZXing.MultiFormatReader(); reader.setHints(hints);
function bitmap(global){
const {data,width,height} = ctx.getImageData(0,0,cv.width,cv.height);
const ls = new ZXing.RGBLuminanceSource(data, width, height);
const bin = global ? new ZXing.GlobalHistogramBinarizer(ls) : new ZXing.HybridBinarizer(ls);
return new ZXing.BinaryBitmap(bin);
}
async function rotate90(){
const t = document.createElement('canvas'), tctx = t.getContext('2d');
t.width = cv.height; t.height = cv.width;
tctx.translate(t.width/2, t.height/2); tctx.rotate(Math.PI/2);
tctx.drawImage(cv, -cv.width/2, -cv.height/2);
cv.width = t.width; cv.height = t.height; ctx.drawImage(t,0,0);
}
function tryDecode(){
try { const r = reader.decode(bitmap(false));
return { text: r.getText ? r.getText() : (r.text || ""),
format: r.getBarcodeFormat ? String(r.getBarcodeFormat()) : (r.barcodeFormat || "CODE") };
} catch(e){ try { const r = reader.decode(bitmap(true));
return { text: r.getText ? r.getText() : (r.text || ""),
format: r.getBarcodeFormat ? String(r.getBarcodeFormat()) : (r.barcodeFormat || "CODE") };
} catch(e2){ return null; } }
}
let res = null;
for (let i=0;i<4 && !res;i++){ res = tryDecode(); if(!res) await rotate90(); }
if (res && res.text) {
document.getElementById('out').textContent = res.format + ": " + res.text;
location.href = "scriptable://decoded?text=" + encodeURIComponent(res.text) + "&format=" + encodeURIComponent(res.format);
} else {
document.getElementById('out').textContent = "Не удалось распознать код";
location.href = "scriptable://decoded?text=&format=";
}
})();
</script>`;
}