diff --git a/README.md b/README.md index 86d8cd0..df5ee6d 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ High-performance metadata scraper for Node.js * Don't download whole contents to get site metadata. * Fetch and parse the content of the `head` element only. Interrupt HTTP request when the `` element starts. - * Download only first few kilobytes to determine image size (by `probe-image-size` package) + * Download only first few kilobytes to determine image size (by `image-dimensions` package) ## Install diff --git a/package.json b/package.json index 12775ac..5ac5617 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "dependencies": { "entities": "^4.5.0", "html-rewriter-wasm": "^0.4.1", - "probe-image-size": "^7.2.3" + "image-dimensions": "^2.3.0" }, "devDependencies": { "@tsconfig/strictest": "^2.0.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3b7cb31..ae547b3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,9 +11,9 @@ dependencies: html-rewriter-wasm: specifier: ^0.4.1 version: 0.4.1 - probe-image-size: - specifier: ^7.2.3 - version: 7.2.3 + image-dimensions: + specifier: ^2.3.0 + version: 2.3.0 devDependencies: '@tsconfig/strictest': @@ -624,28 +624,6 @@ packages: time-zone: 1.0.0 dev: true - /debug@2.6.9: - resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.0.0 - dev: false - - /debug@3.2.7: - resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.3 - dev: false - /debug@4.3.4: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} @@ -848,13 +826,6 @@ packages: resolution: {integrity: sha512-lNovG8CMCCmcVB1Q7xggMSf7tqPCijZXaH4gL6iE8BFghdQCbaY5Met9i1x2Ex8m/cZHDUtXK9H6/znKamRP8Q==} dev: false - /iconv-lite@0.4.24: - resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} - engines: {node: '>=0.10.0'} - dependencies: - safer-buffer: 2.1.2 - dev: false - /ignore-by-default@2.1.0: resolution: {integrity: sha512-yiWd4GVmJp0Q6ghmM2B/V3oZGRmjrKLXvHR3TE1nfoXsmoggllfZUQe74EN0fJdPFZu2NIvNdrMMLm3OsV7Ohw==} engines: {node: '>=10 <11 || >=12 <13 || >=14'} @@ -865,6 +836,12 @@ packages: engines: {node: '>= 4'} dev: true + /image-dimensions@2.3.0: + resolution: {integrity: sha512-8Ar3lsO6+/JLfnUeHnR8Jp/IyQR85Jut5t4Swy1yiXNwj/xM9h5V53v5KE/m/ZSMG4qGRopnSy37uPzKyQCv0A==} + engines: {node: '>=18'} + hasBin: true + dev: false + /imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} @@ -970,10 +947,6 @@ packages: p-locate: 6.0.0 dev: true - /lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - dev: false - /lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} dev: true @@ -1049,28 +1022,13 @@ packages: engines: {node: '>=16 || 14 >=14.17'} dev: true - /ms@2.0.0: - resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - dev: false - /ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} dev: true /ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - /needle@2.9.1: - resolution: {integrity: sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ==} - engines: {node: '>= 4.4.x'} - hasBin: true - dependencies: - debug: 3.2.7 - iconv-lite: 0.4.24 - sax: 1.2.4 - transitivePeerDependencies: - - supports-color - dev: false + dev: true /nofilter@3.1.0: resolution: {integrity: sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==} @@ -1175,16 +1133,6 @@ packages: parse-ms: 3.0.0 dev: true - /probe-image-size@7.2.3: - resolution: {integrity: sha512-HubhG4Rb2UH8YtV4ba0Vp5bQ7L78RTONYu/ujmCu5nBI8wGv24s4E9xSKBi0N1MowRpxk76pFCpJtW0KPzOK0w==} - dependencies: - lodash.merge: 4.6.2 - needle: 2.9.1 - stream-parser: 0.3.1 - transitivePeerDependencies: - - supports-color - dev: false - /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true @@ -1236,14 +1184,6 @@ packages: queue-microtask: 1.2.3 dev: true - /safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - dev: false - - /sax@1.2.4: - resolution: {integrity: sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==} - dev: false - /semver@7.5.4: resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} engines: {node: '>=10'} @@ -1312,14 +1252,6 @@ packages: escape-string-regexp: 2.0.0 dev: true - /stream-parser@0.3.1: - resolution: {integrity: sha512-bJ/HgKq41nlKvlhccD5kaCr/P+Hu0wPNKPJOH7en+YrJu/9EgqUF+88w5Jb6KNcjOFMhfX4B2asfeAtIGuHObQ==} - dependencies: - debug: 2.6.9 - transitivePeerDependencies: - - supports-color - dev: false - /string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} diff --git a/src/fetch-image-size.ts b/src/fetch-image-size.ts new file mode 100644 index 0000000..6b34ecf --- /dev/null +++ b/src/fetch-image-size.ts @@ -0,0 +1,15 @@ +import { imageDimensionsFromStream } from 'image-dimensions' + +export default async function fetchImageSize(url: string, options: RequestInit) { + const controller = new AbortController() + const response = await fetch(url, { + ...options, + signal: controller.signal + }) + if (!response.body) { + return undefined + } + const result = await imageDimensionsFromStream(response.body) + controller.abort() + return result +} diff --git a/src/index.ts b/src/index.ts index 17c60ee..7b809b1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,4 @@ -import imageSize from 'probe-image-size' +import fetchImageSize from './fetch-image-size.js' import extractMetadata from './extract-metadata.js' import type { ImageInfo, Metadata } from './extract-metadata.js' @@ -38,7 +38,7 @@ const defaultFavicon = async (baseUrl: string, fetchOptions: RequestInit) => { return response.ok ? defaultFaviconUrl : undefined } -const fetchImageInfo = async (info: ImageInfo) => { +const fetchImageInfo = async (info: ImageInfo, fetchOptions: RequestInit) => { const intRegex = /0|[1-9][0-9]*/ if (info.width !== undefined && info.height !== undefined && intRegex.test(info.width) && intRegex.test(info.height)) { return { @@ -48,17 +48,16 @@ const fetchImageInfo = async (info: ImageInfo) => { alt: info.alt } } - try { - const actualSize = await imageSize(info.src) + const actualSize = await fetchImageSize(info.src, fetchOptions) + if (actualSize) { return { src: info.src, width: actualSize.width.toString(), height: actualSize.height.toString(), alt: info.alt } - } catch { - return info } + return info } type IntrinsicOptions = { @@ -104,7 +103,7 @@ export default async function fetchSiteMetadata(url: string | URL, options: Opti const [iconUrl, imageInfo] = await Promise.all([ typeof metadata.icon === 'string' ? Promise.resolve(metadata.icon) : defaultFavicon(urlString, fetchOptions), - metadata.image === undefined ? Promise.resolve(undefined) : fetchImageInfo(metadata.image) + metadata.image === undefined ? Promise.resolve(undefined) : fetchImageInfo(metadata.image, fetchOptions) ]) return {