CI / check (push) Canceled after 0s
- License: AGPL-3.0-or-later (LICENSE, every package.json, README). - MUSICSHARE_FOSS=1 builds leave out the only closed-source code, Google's ML Kit / Play Services barcode scanner bundled by expo-camera; the scan screen then decodes small camera snapshots with jsQR instead. - Expo modules build from source rather than from precompiled AARs, as F-Droid requires (that's also what makes the scanner switch take effect). Verified: a FOSS build contains no ML Kit or Play Services classes. - Release builds default to the production server, and come out unsigned without our upload key (F-Droid signs with its own). versionCode 1. - Store listing in fastlane/metadata/android, a draft fdroiddata recipe in fdroid/, and docs/FDROID.md with the submission steps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MzFywujuH9TiuXbr9vjoX8
26 lines
1.1 KiB
TypeScript
26 lines
1.1 KiB
TypeScript
import jpeg from 'jpeg-js';
|
|
import jsQR from 'jsqr';
|
|
|
|
/**
|
|
* Reads a QR code from a small JPEG snapshot (base64), entirely in JS. Used by
|
|
* F-Droid builds, which leave out Google's ML Kit scanner. Returns the code's
|
|
* text, or null if there isn't one.
|
|
*/
|
|
export function decodeQrFromJpeg(base64: string): string | null {
|
|
const bytes = Uint8Array.from(atob(base64), (c) => c.charCodeAt(0));
|
|
const image = jpeg.decode(bytes, { useTArray: true, formatAsRGBA: true, maxResolutionInMP: 4 });
|
|
const code = jsQR(new Uint8ClampedArray(image.data.buffer, image.data.byteOffset, image.data.length), image.width, image.height, {
|
|
inversionAttempts: 'dontInvert',
|
|
});
|
|
return code?.data ?? null;
|
|
}
|
|
|
|
/** The smallest snapshot size that still reads a QR code held at arm's length. */
|
|
export function pickSnapshotSize(sizes: string[]): string | undefined {
|
|
const parsed = sizes
|
|
.map((s) => ({ s, w: Number(s.split('x')[0]), h: Number(s.split('x')[1]) }))
|
|
.filter((p) => p.w > 0 && p.h > 0)
|
|
.sort((a, b) => a.w * a.h - b.w * b.h);
|
|
return (parsed.find((p) => Math.min(p.w, p.h) >= 480) ?? parsed.at(-1))?.s;
|
|
}
|