Skip to content

Commit 95e331a

Browse files
feat: switch to heic-to, better bundling of deps
1 parent 3a47fe1 commit 95e331a

5 files changed

Lines changed: 98 additions & 43 deletions

File tree

src/frontend/package-lock.json

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/frontend/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
"formsnap": "^2.0.1",
6060
"globals": "^17.5.0",
6161
"hash-wasm": "^4.12.0",
62-
"heic2any": "^0.0.4",
62+
"heic-to": "^1.4.3",
6363
"idb": "^8.0.3",
6464
"layerchart": "^2.0.0-next.48",
6565
"mode-watcher": "^1.1.0",

src/frontend/src/app.d.ts

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,4 @@ declare global {
1717
declare const __COMMIT_SHA__: string;
1818
}
1919

20-
declare module 'heic2any' {
21-
type Heic2Any = (options: {
22-
blob: Blob;
23-
toType?: string;
24-
quality?: number;
25-
}) => Promise<Blob | Blob[]>;
26-
const heic2any: Heic2Any;
27-
export default heic2any;
28-
}
29-
3020
export {};

src/frontend/src/lib/components/FileViewerOverlay.svelte

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import { detectMimeFromBlob } from '$lib/functions/mime';
77
import { getImageSupportInfo, type ImageSupportInfo } from '$lib/functions/media-support';
88
9+
const { heicTo } = await import('heic-to');
10+
911
let {
1012
filename,
1113
contentText = null,
@@ -47,11 +49,6 @@
4749
const baseName = $derived(filename.split(/[/\\]/).pop() ?? filename);
4850
4951
type MediaKind = 'image' | 'video' | 'audio' | 'other';
50-
type Heic2Any = (options: {
51-
blob: Blob;
52-
toType?: string;
53-
quality?: number;
54-
}) => Promise<Blob | Blob[]>;
5552
5653
const heicExtensions = ['.heic', '.heif'];
5754
@@ -116,11 +113,8 @@
116113
117114
heicConvertPromise = (async () => {
118115
try {
119-
const { default: heic2any } = (await import('heic2any')) as {
120-
default: Heic2Any;
121-
};
122-
const result = await heic2any({ blob: sourceBlob, toType: 'image/png' });
123-
const pngBlob = Array.isArray(result) ? result[0] : result;
116+
const result = await heicTo({ blob: sourceBlob, type: 'image/png' });
117+
const pngBlob = result instanceof Blob ? result : null;
124118
if (!pngBlob || token !== heicConversionToken) return null;
125119
heicConvertedBlob = pngBlob;
126120
heicConvertedUrl = URL.createObjectURL(pngBlob);

src/frontend/src/lib/functions/media-support.ts

Lines changed: 87 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
import { feature } from 'caniuse-lite';
1+
const { feature } = await import('caniuse-lite');
22

33
// @ts-expect-error: type is not available
4-
import avifData from 'caniuse-lite/data/features/avif';
4+
const { default: avifData } = await import('caniuse-lite/data/features/avif');
55

66
// @ts-expect-error: type is not available
7-
import heifData from 'caniuse-lite/data/features/heif';
7+
const { default: heifData } = await import('caniuse-lite/data/features/heif');
88

99
// @ts-expect-error: type is not available
10-
import webpData from 'caniuse-lite/data/features/webp';
10+
const { default: webpData } = await import('caniuse-lite/data/features/webp');
1111

1212
type CaniuseStats = Record<string, Record<string, string>>;
1313

@@ -68,30 +68,65 @@ const parseIosVersion = (ua: string) => {
6868

6969
const getBrowserInfo = (): BrowserInfo | null => {
7070
if (typeof navigator === 'undefined') return null;
71+
7172
const ua = navigator.userAgent;
7273
const isiOS = /iPad|iPhone|iPod/.test(ua);
7374
const isAndroid = /Android/.test(ua);
7475

7576
if (isiOS) {
7677
const version = parseIosVersion(ua);
7778
if (!version) return null;
78-
return { agent: 'ios_saf', version };
79+
80+
return {
81+
agent: 'ios_saf',
82+
version
83+
};
7984
}
8085

8186
const edgeVersion = parseVersion(ua.match(/Edg\/(\d+(?:\.\d+)?)/)?.[1] ?? null);
82-
if (edgeVersion) return { agent: 'edge', version: edgeVersion };
87+
88+
if (edgeVersion) {
89+
return {
90+
agent: 'edge',
91+
version: edgeVersion
92+
};
93+
}
8394

8495
const operaVersion = parseVersion(ua.match(/OPR\/(\d+(?:\.\d+)?)/)?.[1] ?? null);
85-
if (operaVersion) return { agent: 'opera', version: operaVersion };
96+
97+
if (operaVersion) {
98+
return {
99+
agent: 'opera',
100+
version: operaVersion
101+
};
102+
}
86103

87104
const firefoxVersion = parseVersion(ua.match(/Firefox\/(\d+(?:\.\d+)?)/)?.[1] ?? null);
88-
if (firefoxVersion) return { agent: isAndroid ? 'and_ff' : 'firefox', version: firefoxVersion };
105+
106+
if (firefoxVersion) {
107+
return {
108+
agent: isAndroid ? 'and_ff' : 'firefox',
109+
version: firefoxVersion
110+
};
111+
}
89112

90113
const chromeVersion = parseVersion(ua.match(/Chrome\/(\d+(?:\.\d+)?)/)?.[1] ?? null);
91-
if (chromeVersion) return { agent: isAndroid ? 'and_chr' : 'chrome', version: chromeVersion };
114+
115+
if (chromeVersion) {
116+
return {
117+
agent: isAndroid ? 'and_chr' : 'chrome',
118+
version: chromeVersion
119+
};
120+
}
92121

93122
const safariVersion = parseVersion(ua.match(/Version\/(\d+(?:\.\d+)?)/)?.[1] ?? null);
94-
if (safariVersion && /Safari\//.test(ua)) return { agent: 'safari', version: safariVersion };
123+
124+
if (safariVersion && /Safari\//.test(ua)) {
125+
return {
126+
agent: 'safari',
127+
version: safariVersion
128+
};
129+
}
95130

96131
return null;
97132
};
@@ -101,8 +136,11 @@ const getMinSupportedVersion = (stats: Record<string, string>) => {
101136

102137
for (const [version, support] of Object.entries(stats)) {
103138
if (!isSupported(support)) continue;
139+
104140
const numeric = parseVersion(version.split('-')[0]);
141+
105142
if (numeric === null) continue;
143+
106144
minVersion = minVersion === null ? numeric : Math.min(minVersion, numeric);
107145
}
108146

@@ -114,25 +152,58 @@ const getSupportedAgents = (stats: CaniuseStats) => {
114152

115153
for (const [agent, versions] of Object.entries(stats)) {
116154
if (!Object.hasOwn(agentLabels, agent)) continue;
117-
if (Object.values(versions).some(isSupported)) supported.push(agent as AgentKey);
155+
156+
if (Object.values(versions).some(isSupported)) {
157+
supported.push(agent as AgentKey);
158+
}
118159
}
119160

120161
return supported;
121162
};
122163

123164
export const getImageSupportInfo = (mime: string): ImageSupportInfo => {
124165
const featureData = featureByMime[mime];
125-
if (!featureData) return { status: 'unknown', message: null };
166+
167+
if (!featureData) {
168+
return {
169+
status: 'unknown',
170+
message: null
171+
};
172+
}
126173

127174
const supportedAgents = getSupportedAgents(featureData.stats).map((agent) => agentLabels[agent]);
175+
128176
const message = supportedAgents.length ? `Supported in: ${supportedAgents.join(', ')}.` : null;
177+
129178
const browser = getBrowserInfo();
130-
if (!browser) return { status: 'unknown', message };
179+
180+
if (!browser) {
181+
return {
182+
status: 'unknown',
183+
message
184+
};
185+
}
131186

132187
const agentStats = featureData.stats[browser.agent];
133-
if (!agentStats) return { status: 'unknown', message };
188+
189+
if (!agentStats) {
190+
return {
191+
status: 'unknown',
192+
message
193+
};
194+
}
134195

135196
const minVersion = getMinSupportedVersion(agentStats);
136-
if (minVersion === null) return { status: 'unsupported', message };
137-
return { status: browser.version >= minVersion ? 'supported' : 'unsupported', message };
197+
198+
if (minVersion === null) {
199+
return {
200+
status: 'unsupported',
201+
message
202+
};
203+
}
204+
205+
return {
206+
status: browser.version >= minVersion ? 'supported' : 'unsupported',
207+
message
208+
};
138209
};

0 commit comments

Comments
 (0)