@opensea/seadn 2.3.10 → 2.3.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +10 -13
- package/src/boost.ts +10 -10
- package/src/index.ts +4 -4
- package/src/sdk.spec.ts +28 -31
- package/src/sdk.ts +49 -57
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var a=Object.defineProperty;var
|
|
1
|
+
"use strict";var a=Object.defineProperty;var S=Object.getOwnPropertyDescriptor;var R=Object.getOwnPropertyNames;var U=Object.prototype.hasOwnProperty;var L=(n,e)=>{for(var r in e)a(n,r,{get:e[r],enumerable:!0})},g=(n,e,r,i)=>{if(e&&typeof e=="object"||typeof e=="function")for(let t of R(e))!U.call(n,t)&&t!==r&&a(n,t,{get:()=>e[t],enumerable:!(i=S(e,t))||i.enumerable});return n};var w=n=>g(a({},"__esModule",{value:!0}),n);var y={};L(y,{optimize:()=>h,originalURL:()=>u});module.exports=w(y);var s=[80,250,500,750,1e3,2e3,4e3];function M(n,e){let r=s.find(t=>t>=n),i=s.find(t=>t>=e);if(i===r){let t=s.indexOf(i);i=s[t+1]}return i||s[s.length-1]}function c(n,e){if(e===void 0||e<=1)return n;let r=Number(n)*e;return M(Number(n),r)}function h(n,{width:e,height:r,format:i,quality:t,fit:p,frameTime:f,boost:m}){try{typeof n=="string"&&(n=new URL(n))}catch(B){return n.toString()}if(!(n instanceof URL))return n;n.host==="raw2.seadn.io"&&(n.host="i2.seadn.io");let l=F(n);if(!(v(n)||l)||d(n)&&f===void 0)return u(n);let o=new URLSearchParams;if(f!==void 0)l&&o.set("frame-time",String(f));else if(d(n))return n.toString();if(r!==void 0&&o.set("h",String(c(r,m))),e!==void 0&&o.set("w",String(c(e,m))),i!==void 0&&o.set("format",i),t){if(Number(t)<=0||Number(t)>100)throw new Error("Quality has to be a positive number between 1 and 100");o.set("q",String(t))}return p!==void 0&&o.set("fit",p),n.search=o.toString(),n.toString()}function d(n){let e=b(n);return e==="mp4"||e==="mov"||e==="webm"||e==="m4v"||e==="ogg"||e==="ogv"}function F(n){return d(n)||b(n)==="gif"}function v(n){if(!x(n))return!1;switch(b(n)){case"jpg":case"png":case"jpeg":case"webp":case"avif":case"ico":case"bmp":case"gif":case"tiff":case"tif":case void 0:return!0;default:return!1}}function b(n){let e=n.pathname.split(".");if(!(e.length<=1))return e[e.length-1]}function x(n){return n.hostname.endsWith("seadn.io")}function u(n){try{typeof n=="string"&&(n=new URL(n))}catch(e){return n.toString()}return x(n)&&(n.hostname=N(n)),n.toString()}function N(n){return n.hostname.replace("i2c","raw2").replace("i2","raw2")}0&&(module.exports={optimize,originalURL});
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/boost.ts","../src/sdk.ts"],"sourcesContent":["export {\n
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/boost.ts","../src/sdk.ts"],"sourcesContent":["export {\n MediaFit,\n MediaFormat,\n MediaParams,\n optimize,\n originalURL,\n} from \"./sdk\"\n","const DIMENSIONS_BUCKETS = [80, 250, 500, 750, 1000, 2000, 4000]\n\nfunction findNextBucket(originalSize: number, boosted: number): number {\n const originalBucket = DIMENSIONS_BUCKETS.find(\n bucket => bucket >= originalSize,\n )\n let nextBucket = DIMENSIONS_BUCKETS.find(bucket => bucket >= boosted)\n\n if (nextBucket === originalBucket) {\n const currentIndex = DIMENSIONS_BUCKETS.indexOf(nextBucket!)\n nextBucket = DIMENSIONS_BUCKETS[currentIndex + 1]\n }\n\n return nextBucket || DIMENSIONS_BUCKETS[DIMENSIONS_BUCKETS.length - 1]\n}\n\nexport function boostSize(\n size: number | `${number}`,\n boost: number | undefined,\n): number | `${number}` {\n if (boost === undefined || boost <= 1) {\n return size\n }\n const boosted = Number(size) * boost\n return findNextBucket(Number(size), boosted)\n}\n","import { boostSize } from \"./boost\"\n\nexport type MediaFormat = \"webp\" | \"avif\" | \"jpeg\" | \"png\"\nexport type MediaFit = \"cover\" | \"contain\" | \"fill\" | \"inside\" | \"outside\"\n\nexport type MediaParams = {\n width?: number | `${number}`\n height?: number | `${number}`\n format?: MediaFormat\n quality?: number | `${number}`\n fit?: MediaFit\n frameTime?: number\n boost?: number\n}\n\nexport function optimize(\n image: string | URL,\n { width, height, format, quality, fit, frameTime, boost }: MediaParams,\n): string {\n try {\n if (typeof image === \"string\") {\n image = new URL(image)\n }\n } catch {\n return image.toString()\n }\n\n if (!(image instanceof URL)) {\n return image\n }\n\n if (image.host === \"raw2.seadn.io\") {\n image.host = \"i2.seadn.io\"\n }\n\n const isFrameable = canExtractFrame(image)\n if (!(canBeResized(image) || isFrameable)) {\n return originalURL(image)\n }\n\n // for partial content stremaing\n if (isVideo(image) && frameTime === undefined) {\n return originalURL(image)\n }\n\n const params = new URLSearchParams()\n\n if (frameTime !== undefined) {\n if (isFrameable) {\n params.set(\"frame-time\", String(frameTime))\n }\n } else if (isVideo(image)) {\n return image.toString()\n }\n\n if (height !== undefined) {\n params.set(\"h\", String(boostSize(height, boost)))\n }\n if (width !== undefined) {\n params.set(\"w\", String(boostSize(width, boost)))\n }\n if (format !== undefined) {\n params.set(\"format\", format)\n }\n if (quality) {\n if (Number(quality) <= 0 || Number(quality) > 100) {\n throw new Error(\"Quality has to be a positive number between 1 and 100\")\n }\n params.set(\"q\", String(quality))\n }\n if (fit !== undefined) {\n params.set(\"fit\", fit)\n }\n\n image.search = params.toString()\n return image.toString()\n}\n\nfunction isVideo(url: URL): boolean {\n const extension = getExtension(url)\n return (\n extension === \"mp4\" ||\n extension === \"mov\" ||\n extension === \"webm\" ||\n extension === \"m4v\" ||\n extension === \"ogg\" ||\n extension === \"ogv\"\n )\n}\n\nfunction canExtractFrame(url: URL): boolean {\n return isVideo(url) || getExtension(url) === \"gif\"\n}\n\nfunction canBeResized(url: URL): boolean {\n if (!isSeadnURL(url)) {\n return false\n }\n const extension = getExtension(url)\n switch (extension) {\n case \"jpg\":\n case \"png\":\n case \"jpeg\":\n case \"webp\":\n case \"avif\":\n case \"ico\":\n case \"bmp\":\n case \"gif\":\n case \"tiff\":\n case \"tif\":\n case undefined:\n return true\n default:\n return false\n }\n}\n\nfunction getExtension(url: URL): string | undefined {\n const split = url.pathname.split(\".\")\n if (split.length <= 1) {\n return\n }\n return split[split.length - 1]\n}\n\nexport function isSeadnURL(url: URL): boolean {\n return url.hostname.endsWith(\"seadn.io\")\n}\n\nexport function originalURL(image: URL | string): string {\n try {\n if (typeof image === \"string\") {\n image = new URL(image)\n }\n } catch {\n return image.toString()\n }\n\n if (!isSeadnURL(image)) {\n return image.toString()\n }\n\n image.hostname = getOriginalHostname(image)\n return image.toString()\n}\n\nexport function getOriginalHostname(url: URL): string {\n return url.hostname.replace(\"i2c\", \"raw2\").replace(\"i2\", \"raw2\")\n}\n"],"mappings":"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","names":["index_exports","__export","optimize","originalURL","__toCommonJS","DIMENSIONS_BUCKETS","findNextBucket","originalSize","boosted","originalBucket","bucket","nextBucket","currentIndex","boostSize","size","boost","optimize","image","width","height","format","quality","fit","frameTime","boost","e","isFrameable","canExtractFrame","canBeResized","isVideo","originalURL","params","boostSize","url","extension","getExtension","isSeadnURL","split","getOriginalHostname"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var s=[80,250,500,750,1e3,2e3,4e3];function
|
|
1
|
+
var s=[80,250,500,750,1e3,2e3,4e3];function h(n,e){let o=s.find(t=>t>=n),r=s.find(t=>t>=e);if(r===o){let t=s.indexOf(r);r=s[t+1]}return r||s[s.length-1]}function f(n,e){if(e===void 0||e<=1)return n;let o=Number(n)*e;return h(Number(n),o)}function x(n,{width:e,height:o,format:r,quality:t,fit:b,frameTime:u,boost:p}){try{typeof n=="string"&&(n=new URL(n))}catch(L){return n.toString()}if(!(n instanceof URL))return n;n.host==="raw2.seadn.io"&&(n.host="i2.seadn.io");let m=S(n);if(!(R(n)||m)||a(n)&&u===void 0)return c(n);let i=new URLSearchParams;if(u!==void 0)m&&i.set("frame-time",String(u));else if(a(n))return n.toString();if(o!==void 0&&i.set("h",String(f(o,p))),e!==void 0&&i.set("w",String(f(e,p))),r!==void 0&&i.set("format",r),t){if(Number(t)<=0||Number(t)>100)throw new Error("Quality has to be a positive number between 1 and 100");i.set("q",String(t))}return b!==void 0&&i.set("fit",b),n.search=i.toString(),n.toString()}function a(n){let e=d(n);return e==="mp4"||e==="mov"||e==="webm"||e==="m4v"||e==="ogg"||e==="ogv"}function S(n){return a(n)||d(n)==="gif"}function R(n){if(!l(n))return!1;switch(d(n)){case"jpg":case"png":case"jpeg":case"webp":case"avif":case"ico":case"bmp":case"gif":case"tiff":case"tif":case void 0:return!0;default:return!1}}function d(n){let e=n.pathname.split(".");if(!(e.length<=1))return e[e.length-1]}function l(n){return n.hostname.endsWith("seadn.io")}function c(n){try{typeof n=="string"&&(n=new URL(n))}catch(e){return n.toString()}return l(n)&&(n.hostname=U(n)),n.toString()}function U(n){return n.hostname.replace("i2c","raw2").replace("i2","raw2")}export{x as optimize,c as originalURL};
|
|
2
2
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/boost.ts","../src/sdk.ts"],"sourcesContent":["const DIMENSIONS_BUCKETS = [80, 250, 500, 750, 1000, 2000, 4000]
|
|
1
|
+
{"version":3,"sources":["../src/boost.ts","../src/sdk.ts"],"sourcesContent":["const DIMENSIONS_BUCKETS = [80, 250, 500, 750, 1000, 2000, 4000]\n\nfunction findNextBucket(originalSize: number, boosted: number): number {\n const originalBucket = DIMENSIONS_BUCKETS.find(\n bucket => bucket >= originalSize,\n )\n let nextBucket = DIMENSIONS_BUCKETS.find(bucket => bucket >= boosted)\n\n if (nextBucket === originalBucket) {\n const currentIndex = DIMENSIONS_BUCKETS.indexOf(nextBucket!)\n nextBucket = DIMENSIONS_BUCKETS[currentIndex + 1]\n }\n\n return nextBucket || DIMENSIONS_BUCKETS[DIMENSIONS_BUCKETS.length - 1]\n}\n\nexport function boostSize(\n size: number | `${number}`,\n boost: number | undefined,\n): number | `${number}` {\n if (boost === undefined || boost <= 1) {\n return size\n }\n const boosted = Number(size) * boost\n return findNextBucket(Number(size), boosted)\n}\n","import { boostSize } from \"./boost\"\n\nexport type MediaFormat = \"webp\" | \"avif\" | \"jpeg\" | \"png\"\nexport type MediaFit = \"cover\" | \"contain\" | \"fill\" | \"inside\" | \"outside\"\n\nexport type MediaParams = {\n width?: number | `${number}`\n height?: number | `${number}`\n format?: MediaFormat\n quality?: number | `${number}`\n fit?: MediaFit\n frameTime?: number\n boost?: number\n}\n\nexport function optimize(\n image: string | URL,\n { width, height, format, quality, fit, frameTime, boost }: MediaParams,\n): string {\n try {\n if (typeof image === \"string\") {\n image = new URL(image)\n }\n } catch {\n return image.toString()\n }\n\n if (!(image instanceof URL)) {\n return image\n }\n\n if (image.host === \"raw2.seadn.io\") {\n image.host = \"i2.seadn.io\"\n }\n\n const isFrameable = canExtractFrame(image)\n if (!(canBeResized(image) || isFrameable)) {\n return originalURL(image)\n }\n\n // for partial content stremaing\n if (isVideo(image) && frameTime === undefined) {\n return originalURL(image)\n }\n\n const params = new URLSearchParams()\n\n if (frameTime !== undefined) {\n if (isFrameable) {\n params.set(\"frame-time\", String(frameTime))\n }\n } else if (isVideo(image)) {\n return image.toString()\n }\n\n if (height !== undefined) {\n params.set(\"h\", String(boostSize(height, boost)))\n }\n if (width !== undefined) {\n params.set(\"w\", String(boostSize(width, boost)))\n }\n if (format !== undefined) {\n params.set(\"format\", format)\n }\n if (quality) {\n if (Number(quality) <= 0 || Number(quality) > 100) {\n throw new Error(\"Quality has to be a positive number between 1 and 100\")\n }\n params.set(\"q\", String(quality))\n }\n if (fit !== undefined) {\n params.set(\"fit\", fit)\n }\n\n image.search = params.toString()\n return image.toString()\n}\n\nfunction isVideo(url: URL): boolean {\n const extension = getExtension(url)\n return (\n extension === \"mp4\" ||\n extension === \"mov\" ||\n extension === \"webm\" ||\n extension === \"m4v\" ||\n extension === \"ogg\" ||\n extension === \"ogv\"\n )\n}\n\nfunction canExtractFrame(url: URL): boolean {\n return isVideo(url) || getExtension(url) === \"gif\"\n}\n\nfunction canBeResized(url: URL): boolean {\n if (!isSeadnURL(url)) {\n return false\n }\n const extension = getExtension(url)\n switch (extension) {\n case \"jpg\":\n case \"png\":\n case \"jpeg\":\n case \"webp\":\n case \"avif\":\n case \"ico\":\n case \"bmp\":\n case \"gif\":\n case \"tiff\":\n case \"tif\":\n case undefined:\n return true\n default:\n return false\n }\n}\n\nfunction getExtension(url: URL): string | undefined {\n const split = url.pathname.split(\".\")\n if (split.length <= 1) {\n return\n }\n return split[split.length - 1]\n}\n\nexport function isSeadnURL(url: URL): boolean {\n return url.hostname.endsWith(\"seadn.io\")\n}\n\nexport function originalURL(image: URL | string): string {\n try {\n if (typeof image === \"string\") {\n image = new URL(image)\n }\n } catch {\n return image.toString()\n }\n\n if (!isSeadnURL(image)) {\n return image.toString()\n }\n\n image.hostname = getOriginalHostname(image)\n return image.toString()\n}\n\nexport function getOriginalHostname(url: URL): string {\n return url.hostname.replace(\"i2c\", \"raw2\").replace(\"i2\", \"raw2\")\n}\n"],"mappings":"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","names":["DIMENSIONS_BUCKETS","findNextBucket","originalSize","boosted","originalBucket","bucket","nextBucket","currentIndex","boostSize","size","boost","optimize","image","width","height","format","quality","fit","frameTime","boost","e","isFrameable","canExtractFrame","canBeResized","isVideo","originalURL","params","boostSize","url","extension","getExtension","isSeadnURL","split","getOriginalHostname"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opensea/seadn",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.11",
|
|
4
4
|
"description": "Javascript SDK to work with SeaDN",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "OpenSea Developers",
|
|
@@ -8,20 +8,17 @@
|
|
|
8
8
|
"main": "./src/index.ts",
|
|
9
9
|
"module": "./dist/index.mjs",
|
|
10
10
|
"types": "./dist/index.d.ts",
|
|
11
|
-
"files": [
|
|
12
|
-
"./dist",
|
|
13
|
-
"./src"
|
|
14
|
-
],
|
|
15
|
-
"devDependencies": {
|
|
16
|
-
"@arethetypeswrong/cli": "0.18.2",
|
|
17
|
-
"tsup": "8.5.0",
|
|
18
|
-
"typescript": "5.8.3",
|
|
19
|
-
"vitest": "1.5.0"
|
|
20
|
-
},
|
|
11
|
+
"files": ["./dist", "./src"],
|
|
21
12
|
"scripts": {
|
|
22
13
|
"build": "tsup",
|
|
23
14
|
"build:typecheck": "attw --pack",
|
|
24
15
|
"test": "vitest",
|
|
25
|
-
"
|
|
16
|
+
"type-check": "tsc"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@arethetypeswrong/cli": "0.18.2",
|
|
20
|
+
"tsup": "8.5.1",
|
|
21
|
+
"typescript": "5.9.2",
|
|
22
|
+
"vitest": "3.2.4"
|
|
26
23
|
}
|
|
27
|
-
}
|
|
24
|
+
}
|
package/src/boost.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
const DIMENSIONS_BUCKETS = [80, 250, 500, 750, 1000, 2000, 4000]
|
|
1
|
+
const DIMENSIONS_BUCKETS = [80, 250, 500, 750, 1000, 2000, 4000]
|
|
2
2
|
|
|
3
3
|
function findNextBucket(originalSize: number, boosted: number): number {
|
|
4
|
-
|
|
4
|
+
const originalBucket = DIMENSIONS_BUCKETS.find(
|
|
5
5
|
bucket => bucket >= originalSize,
|
|
6
|
-
)
|
|
7
|
-
let nextBucket = DIMENSIONS_BUCKETS.find(bucket => bucket >= boosted)
|
|
6
|
+
)
|
|
7
|
+
let nextBucket = DIMENSIONS_BUCKETS.find(bucket => bucket >= boosted)
|
|
8
8
|
|
|
9
9
|
if (nextBucket === originalBucket) {
|
|
10
|
-
const currentIndex = DIMENSIONS_BUCKETS.indexOf(nextBucket!)
|
|
11
|
-
nextBucket = DIMENSIONS_BUCKETS[currentIndex + 1]
|
|
10
|
+
const currentIndex = DIMENSIONS_BUCKETS.indexOf(nextBucket!)
|
|
11
|
+
nextBucket = DIMENSIONS_BUCKETS[currentIndex + 1]
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
return nextBucket || DIMENSIONS_BUCKETS[DIMENSIONS_BUCKETS.length - 1]
|
|
14
|
+
return nextBucket || DIMENSIONS_BUCKETS[DIMENSIONS_BUCKETS.length - 1]
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export function boostSize(
|
|
@@ -19,8 +19,8 @@ export function boostSize(
|
|
|
19
19
|
boost: number | undefined,
|
|
20
20
|
): number | `${number}` {
|
|
21
21
|
if (boost === undefined || boost <= 1) {
|
|
22
|
-
return size
|
|
22
|
+
return size
|
|
23
23
|
}
|
|
24
|
-
const boosted = Number(size) * boost
|
|
25
|
-
return findNextBucket(Number(size), boosted)
|
|
24
|
+
const boosted = Number(size) * boost
|
|
25
|
+
return findNextBucket(Number(size), boosted)
|
|
26
26
|
}
|
package/src/index.ts
CHANGED
package/src/sdk.spec.ts
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { expect, test } from "vitest"
|
|
2
|
+
import { isSeadnURL, type MediaParams, optimize, originalURL } from "./sdk"
|
|
3
3
|
|
|
4
4
|
test.each([
|
|
5
5
|
[undefined, {} satisfies MediaParams, undefined],
|
|
6
|
+
[null, {} satisfies MediaParams, null],
|
|
6
7
|
["", {} satisfies MediaParams, ""],
|
|
7
8
|
["random", {} satisfies MediaParams, "random"],
|
|
8
9
|
[[], {} satisfies MediaParams, []],
|
|
9
10
|
[{}, {} satisfies MediaParams, {}],
|
|
11
|
+
[
|
|
12
|
+
"https://random.io/image.png",
|
|
13
|
+
{ width: 24, height: 24, frameTime: 1 } satisfies MediaParams,
|
|
14
|
+
"https://random.io/image.png",
|
|
15
|
+
],
|
|
10
16
|
[
|
|
11
17
|
"https://i2.seadn.io/bored-ape.png",
|
|
12
18
|
{} satisfies MediaParams,
|
|
@@ -150,34 +156,31 @@ test.each([
|
|
|
150
156
|
],
|
|
151
157
|
[
|
|
152
158
|
"https://raw2.seadn.io/bored-ape.png",
|
|
153
|
-
{ width: 24, height: 24
|
|
154
|
-
"https://i2.seadn.io/bored-ape.png?h=
|
|
159
|
+
{ width: 24, height: 24 } satisfies MediaParams,
|
|
160
|
+
"https://i2.seadn.io/bored-ape.png?h=24&w=24",
|
|
155
161
|
],
|
|
156
162
|
[
|
|
157
|
-
"https://
|
|
158
|
-
{ width:
|
|
159
|
-
"https://
|
|
163
|
+
"https://raw2.seadn.io/bored-ape.mp4",
|
|
164
|
+
{ width: 24, height: 24 } satisfies MediaParams,
|
|
165
|
+
"https://raw2.seadn.io/bored-ape.mp4",
|
|
166
|
+
],
|
|
167
|
+
[
|
|
168
|
+
"https://raw2.seadn.io/bored-ape.mp4",
|
|
169
|
+
{ width: 24, height: 24, frameTime: 1 } satisfies MediaParams,
|
|
170
|
+
"https://i2.seadn.io/bored-ape.mp4?frame-time=1&h=24&w=24",
|
|
160
171
|
],
|
|
161
172
|
])("optimize(%o, %o) -> %o", (url, resizeParams, expected) => {
|
|
162
|
-
expect(optimize(url as string, resizeParams)).toEqual(expected)
|
|
163
|
-
})
|
|
173
|
+
expect(optimize(url as string, resizeParams)).toEqual(expected)
|
|
174
|
+
})
|
|
164
175
|
|
|
165
176
|
test.each([
|
|
166
|
-
[
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
true,
|
|
171
|
-
],
|
|
172
|
-
[
|
|
173
|
-
new URL(
|
|
174
|
-
"https://i.seadn.io/s/raw/files/d89900cc5ecd6cabd26f835a32860f62.jpg",
|
|
175
|
-
),
|
|
176
|
-
true,
|
|
177
|
-
],
|
|
177
|
+
[new URL("https://raw2.seadn.io"), true],
|
|
178
|
+
[new URL("https://i2.seadn.io"), true],
|
|
179
|
+
[new URL("https://i2c.seadn.io"), true],
|
|
180
|
+
[new URL("https://random.io"), false],
|
|
178
181
|
])("isSeadnURL(%s) -> %o", (url, expected) => {
|
|
179
|
-
expect(isSeadnURL(url)).toEqual(expected)
|
|
180
|
-
})
|
|
182
|
+
expect(isSeadnURL(url)).toEqual(expected)
|
|
183
|
+
})
|
|
181
184
|
|
|
182
185
|
test.each([
|
|
183
186
|
["https://i2.seadn.io/bored-ape.gif", "https://raw2.seadn.io/bored-ape.gif"],
|
|
@@ -186,12 +189,6 @@ test.each([
|
|
|
186
189
|
new URL("https://i2.seadn.io/bored-ape.gif"),
|
|
187
190
|
"https://raw2.seadn.io/bored-ape.gif",
|
|
188
191
|
],
|
|
189
|
-
[
|
|
190
|
-
new URL(
|
|
191
|
-
"https://i.seadn.io/s/raw/files/ac1a6cc163abcee90299a15d2ebbe746.html",
|
|
192
|
-
),
|
|
193
|
-
"https://raw.seadn.io/files/ac1a6cc163abcee90299a15d2ebbe746.html",
|
|
194
|
-
],
|
|
195
192
|
])("originalURL(%s) -> %o", (url, expected) => {
|
|
196
|
-
expect(originalURL(url)).toEqual(expected)
|
|
197
|
-
})
|
|
193
|
+
expect(originalURL(url)).toEqual(expected)
|
|
194
|
+
})
|
package/src/sdk.ts
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { boostSize } from "./boost"
|
|
1
|
+
import { boostSize } from "./boost"
|
|
2
2
|
|
|
3
|
-
export type MediaFormat = "webp" | "avif" | "jpeg" | "png"
|
|
4
|
-
export type MediaFit = "cover" | "contain" | "fill" | "inside" | "outside"
|
|
3
|
+
export type MediaFormat = "webp" | "avif" | "jpeg" | "png"
|
|
4
|
+
export type MediaFit = "cover" | "contain" | "fill" | "inside" | "outside"
|
|
5
5
|
|
|
6
6
|
export type MediaParams = {
|
|
7
|
-
width?: number | `${number}
|
|
8
|
-
height?: number | `${number}
|
|
9
|
-
format?: MediaFormat
|
|
10
|
-
quality?: number | `${number}
|
|
11
|
-
fit?: MediaFit
|
|
12
|
-
frameTime?: number
|
|
13
|
-
boost?: number
|
|
14
|
-
}
|
|
7
|
+
width?: number | `${number}`
|
|
8
|
+
height?: number | `${number}`
|
|
9
|
+
format?: MediaFormat
|
|
10
|
+
quality?: number | `${number}`
|
|
11
|
+
fit?: MediaFit
|
|
12
|
+
frameTime?: number
|
|
13
|
+
boost?: number
|
|
14
|
+
}
|
|
15
15
|
|
|
16
16
|
export function optimize(
|
|
17
17
|
image: string | URL,
|
|
@@ -19,65 +19,65 @@ export function optimize(
|
|
|
19
19
|
): string {
|
|
20
20
|
try {
|
|
21
21
|
if (typeof image === "string") {
|
|
22
|
-
image = new URL(image)
|
|
22
|
+
image = new URL(image)
|
|
23
23
|
}
|
|
24
24
|
} catch {
|
|
25
|
-
return image.toString()
|
|
25
|
+
return image.toString()
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
if (!(image instanceof URL)) {
|
|
29
|
-
return image
|
|
29
|
+
return image
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
if (image.host === "raw2.seadn.io") {
|
|
33
|
-
image.host = "i2.seadn.io"
|
|
33
|
+
image.host = "i2.seadn.io"
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
const isFrameable = canExtractFrame(image)
|
|
37
|
-
if (!canBeResized(image)
|
|
38
|
-
return originalURL(image)
|
|
36
|
+
const isFrameable = canExtractFrame(image)
|
|
37
|
+
if (!(canBeResized(image) || isFrameable)) {
|
|
38
|
+
return originalURL(image)
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
// for partial content stremaing
|
|
42
42
|
if (isVideo(image) && frameTime === undefined) {
|
|
43
|
-
return originalURL(image)
|
|
43
|
+
return originalURL(image)
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
const params = new URLSearchParams()
|
|
46
|
+
const params = new URLSearchParams()
|
|
47
47
|
|
|
48
48
|
if (frameTime !== undefined) {
|
|
49
49
|
if (isFrameable) {
|
|
50
|
-
params.set("frame-time", String(frameTime))
|
|
50
|
+
params.set("frame-time", String(frameTime))
|
|
51
51
|
}
|
|
52
52
|
} else if (isVideo(image)) {
|
|
53
|
-
return image.toString()
|
|
53
|
+
return image.toString()
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
if (height !== undefined) {
|
|
57
|
-
params.set("h", String(boostSize(height, boost)))
|
|
57
|
+
params.set("h", String(boostSize(height, boost)))
|
|
58
58
|
}
|
|
59
59
|
if (width !== undefined) {
|
|
60
|
-
params.set("w", String(boostSize(width, boost)))
|
|
60
|
+
params.set("w", String(boostSize(width, boost)))
|
|
61
61
|
}
|
|
62
62
|
if (format !== undefined) {
|
|
63
|
-
params.set("format", format)
|
|
63
|
+
params.set("format", format)
|
|
64
64
|
}
|
|
65
65
|
if (quality) {
|
|
66
66
|
if (Number(quality) <= 0 || Number(quality) > 100) {
|
|
67
|
-
throw new Error("Quality has to be a positive number between 1 and 100")
|
|
67
|
+
throw new Error("Quality has to be a positive number between 1 and 100")
|
|
68
68
|
}
|
|
69
|
-
params.set("q", String(quality))
|
|
69
|
+
params.set("q", String(quality))
|
|
70
70
|
}
|
|
71
71
|
if (fit !== undefined) {
|
|
72
|
-
params.set("fit", fit)
|
|
72
|
+
params.set("fit", fit)
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
image.search = params.toString()
|
|
76
|
-
return image.toString()
|
|
75
|
+
image.search = params.toString()
|
|
76
|
+
return image.toString()
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
function isVideo(url: URL): boolean {
|
|
80
|
-
const extension = getExtension(url)
|
|
80
|
+
const extension = getExtension(url)
|
|
81
81
|
return (
|
|
82
82
|
extension === "mp4" ||
|
|
83
83
|
extension === "mov" ||
|
|
@@ -85,18 +85,18 @@ function isVideo(url: URL): boolean {
|
|
|
85
85
|
extension === "m4v" ||
|
|
86
86
|
extension === "ogg" ||
|
|
87
87
|
extension === "ogv"
|
|
88
|
-
)
|
|
88
|
+
)
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
function canExtractFrame(url: URL): boolean {
|
|
92
|
-
return isVideo(url) || getExtension(url) === "gif"
|
|
92
|
+
return isVideo(url) || getExtension(url) === "gif"
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
function canBeResized(url: URL): boolean {
|
|
96
96
|
if (!isSeadnURL(url)) {
|
|
97
|
-
return false
|
|
97
|
+
return false
|
|
98
98
|
}
|
|
99
|
-
const extension = getExtension(url)
|
|
99
|
+
const extension = getExtension(url)
|
|
100
100
|
switch (extension) {
|
|
101
101
|
case "jpg":
|
|
102
102
|
case "png":
|
|
@@ -106,52 +106,44 @@ function canBeResized(url: URL): boolean {
|
|
|
106
106
|
case "ico":
|
|
107
107
|
case "bmp":
|
|
108
108
|
case "gif":
|
|
109
|
+
case "tiff":
|
|
110
|
+
case "tif":
|
|
109
111
|
case undefined:
|
|
110
|
-
return true
|
|
112
|
+
return true
|
|
111
113
|
default:
|
|
112
|
-
return false
|
|
114
|
+
return false
|
|
113
115
|
}
|
|
114
116
|
}
|
|
115
117
|
|
|
116
118
|
function getExtension(url: URL): string | undefined {
|
|
117
|
-
const split = url.pathname.split(".")
|
|
119
|
+
const split = url.pathname.split(".")
|
|
118
120
|
if (split.length <= 1) {
|
|
119
|
-
return
|
|
121
|
+
return
|
|
120
122
|
}
|
|
121
|
-
return split[split.length - 1]
|
|
123
|
+
return split[split.length - 1]
|
|
122
124
|
}
|
|
123
125
|
|
|
124
126
|
export function isSeadnURL(url: URL): boolean {
|
|
125
|
-
return url.hostname.endsWith("seadn.io")
|
|
127
|
+
return url.hostname.endsWith("seadn.io")
|
|
126
128
|
}
|
|
127
129
|
|
|
128
130
|
export function originalURL(image: URL | string): string {
|
|
129
131
|
try {
|
|
130
132
|
if (typeof image === "string") {
|
|
131
|
-
image = new URL(image)
|
|
133
|
+
image = new URL(image)
|
|
132
134
|
}
|
|
133
135
|
} catch {
|
|
134
|
-
return image.toString()
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
if (isSeadnV1URL(image)) {
|
|
138
|
-
image.hostname = image.hostname.replace("i.seadn.io", "raw.seadn.io");
|
|
139
|
-
image.pathname = image.pathname.replace("/s/raw/files/", "/files/");
|
|
140
|
-
return image.toString();
|
|
136
|
+
return image.toString()
|
|
141
137
|
}
|
|
142
138
|
|
|
143
139
|
if (!isSeadnURL(image)) {
|
|
144
|
-
return image.toString()
|
|
140
|
+
return image.toString()
|
|
145
141
|
}
|
|
146
142
|
|
|
147
|
-
image.hostname = getOriginalHostname(image)
|
|
148
|
-
return image.toString()
|
|
143
|
+
image.hostname = getOriginalHostname(image)
|
|
144
|
+
return image.toString()
|
|
149
145
|
}
|
|
150
146
|
|
|
151
147
|
export function getOriginalHostname(url: URL): string {
|
|
152
|
-
return url.hostname.replace("i2c", "raw2").replace("i2", "raw2")
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
export function isSeadnV1URL(url: URL): boolean {
|
|
156
|
-
return url.hostname === "i.seadn.io" || url.hostname === "raw.seadn.io";
|
|
148
|
+
return url.hostname.replace("i2c", "raw2").replace("i2", "raw2")
|
|
157
149
|
}
|