Skip to content
This repository has been archived by the owner on Mar 12, 2023. It is now read-only.

Fetch image size #50

Merged
merged 7 commits into from Feb 23, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
52 changes: 36 additions & 16 deletions __tests__/pages/blog/__snapshots__/[slug].test.tsx.snap
Expand Up @@ -168,11 +168,11 @@ exports[`RenderPost renders the page unchanged 1`] = `
</span>
</code>
</pre>
<div
<figcaption
class="caption"
>
This is code caption.
</div>
</figcaption>
</div>
<p />
<blockquote>
Expand Down Expand Up @@ -216,52 +216,72 @@ exports[`RenderPost renders the page unchanged 1`] = `
</tbody>
</table>
<p />
<div
<figure
class="image"
>
<div>
<span
style="box-sizing: border-box; display: block; overflow: hidden; background: none; opacity: 1; border: 0px; margin: 0px; padding: 0px; position: absolute; top: 0px; left: 0px; bottom: 0px; right: 0px;"
style="box-sizing: border-box; display: inline-block; overflow: hidden; background: none; opacity: 1; border: 0px; margin: 0px; padding: 0px; position: relative; max-width: 100%;"
>
<span
style="box-sizing: border-box; display: block; background: none; opacity: 1; border: 0px; margin: 0px; padding: 0px; max-width: 100%;"
>
<img
alt=""
aria-hidden="true"
src="data:image/svg+xml,%3csvg%20xmlns=%27http://www.w3.org/2000/svg%27%20version=%271.1%27%20width=%27100%27%20height=%27100%27/%3e"
style="display: block; max-width: 100%; background: none; opacity: 1; border: 0px; margin: 0px; padding: 0px;"
/>
</span>
<img
alt="画像が読み込まれない場合はページを更新してみてください。"
data-nimg="fill"
data-nimg="intrinsic"
decoding="async"
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
style="position: absolute; top: 0px; left: 0px; bottom: 0px; right: 0px; box-sizing: border-box; padding: 0px; margin: auto; display: block; width: 0px; height: 0px; min-width: 100%; max-width: 100%; min-height: 100%; max-height: 100%; object-fit: contain;"
style="position: absolute; top: 0px; left: 0px; bottom: 0px; right: 0px; box-sizing: border-box; padding: 0px; margin: auto; display: block; width: 0px; height: 0px; min-width: 100%; max-width: 100%; min-height: 100%; max-height: 100%;"
/>
<noscript />
</span>
</div>
<div
<figcaption
class="caption"
>
This is image caption.
</div>
</div>
<div
</figcaption>
</figure>
<figure
class="image"
>
<div>
<span
style="box-sizing: border-box; display: block; overflow: hidden; background: none; opacity: 1; border: 0px; margin: 0px; padding: 0px; position: absolute; top: 0px; left: 0px; bottom: 0px; right: 0px;"
style="box-sizing: border-box; display: inline-block; overflow: hidden; background: none; opacity: 1; border: 0px; margin: 0px; padding: 0px; position: relative; max-width: 100%;"
>
<span
style="box-sizing: border-box; display: block; background: none; opacity: 1; border: 0px; margin: 0px; padding: 0px; max-width: 100%;"
>
<img
alt=""
aria-hidden="true"
src="data:image/svg+xml,%3csvg%20xmlns=%27http://www.w3.org/2000/svg%27%20version=%271.1%27%20width=%27100%27%20height=%27100%27/%3e"
style="display: block; max-width: 100%; background: none; opacity: 1; border: 0px; margin: 0px; padding: 0px;"
/>
</span>
<img
alt="画像が読み込まれない場合はページを更新してみてください。"
data-nimg="fill"
data-nimg="intrinsic"
decoding="async"
src="data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"
style="position: absolute; top: 0px; left: 0px; bottom: 0px; right: 0px; box-sizing: border-box; padding: 0px; margin: auto; display: block; width: 0px; height: 0px; min-width: 100%; max-width: 100%; min-height: 100%; max-height: 100%; object-fit: contain;"
style="position: absolute; top: 0px; left: 0px; bottom: 0px; right: 0px; box-sizing: border-box; padding: 0px; margin: auto; display: block; width: 0px; height: 0px; min-width: 100%; max-width: 100%; min-height: 100%; max-height: 100%;"
/>
<noscript />
</span>
</div>
<div
<figcaption
class="caption"
>
External images from Unsplash
</div>
</div>
</figcaption>
</figure>
</div>
<footer>
<ul
Expand Down
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -22,6 +22,7 @@
"@zeit/react-jsx-parser": "^2.0.0",
"async-sema": "^3.1.0",
"github-slugger": "^1.2.1",
"image-size": "^1.0.1",
"mermaid": "^8.14.0",
"next": "12",
"prismjs": "^1.25.0",
Expand Down
19 changes: 13 additions & 6 deletions src/components/notion-block.tsx
Expand Up @@ -59,28 +59,35 @@ const Heading = ({ block, level = 1 }) => {
)
}

const Caption = ({ caption }) => {
const Caption = ({ caption, type = 'figure' }) => {
if (caption.length === 0 || !caption[0].Text.Content) return null

if (type === 'figure') {
return (
<figcaption className={styles.caption}>
{caption[0].Text.Content}
</figcaption>
)
}
return <div className={styles.caption}>{caption[0].Text.Content}</div>
}

const ImageBlock = ({ block }) => (
<div className={styles.image}>
<figure className={styles.image}>
<div>
<Image
src={
block.Image.External
? block.Image.External.Url
: `/notion_images/${block.Id}.png`
}
layout="fill"
objectFit="contain"
width={block.Image.Width || 100}
height={block.Image.Height || 100}
alt="画像が読み込まれない場合はページを更新してみてください。"
/>
</div>
<Caption caption={block.Image.Caption} />
</div>
<Caption caption={block.Image.Caption} type="figure" />
</figure>
)

const Code = ({ block }) => {
Expand Down
17 changes: 16 additions & 1 deletion src/lib/notion/client.ts
Expand Up @@ -20,6 +20,7 @@ import {
const { Client } = require('@notionhq/client')
import * as blogIndexCache from './blog-index-cache'
import * as imageCache from './image-cache'
import { fetchImageAsBlob, getImageSize } from './image-utils'

const client = new Client({
auth: NOTION_API_SECRET,
Expand Down Expand Up @@ -299,7 +300,6 @@ export async function getAllBlocksByBlockId(blockId) {
if (item.image.type === 'external') {
image.External = { Url: item.image.external.url }
} else {
imageCache.store(item.id, item.image.file.url)
image.File = { Url: item.image.file.url }
}

Expand Down Expand Up @@ -449,6 +449,21 @@ export async function getAllBlocksByBlockId(blockId) {
if (block.Type === 'table') {
// Fetch table_row
block.Table.Rows = await getAllBlocksByBlockId(block.Id)
} else if (block.Type === 'image') {
// Get image size and cache to local (only type: file)
const blob = await fetchImageAsBlob(
block.Image.File ? block.Image.File.Url : block.Image.External.Url
)
const dimensions = await getImageSize(blob)

if (dimensions) {
block.Image.Width = dimensions.width
block.Image.Height = dimensions.height
}

if (block.Image.File) {
imageCache.store(block.Id, blob)
}
}
}

Expand Down
13 changes: 1 addition & 12 deletions src/lib/notion/image-cache.ts
@@ -1,8 +1,6 @@
import * as fs from 'fs'

export const store = async (id: string, url: string) => {
const blob = await fetchImageAsBlob(url)

export const store = async (id: string, blob: Blob) => {
if (!blob) {
return
}
Expand All @@ -22,12 +20,3 @@ const dir = 'public/notion_images'
const filePath = (id: string) => {
return `${dir}/${id}.png`
}

const fetchImageAsBlob = async (url: string) => {
try {
return await fetch(url).then(res => res.blob())
} catch (err) {
console.log(err)
return null
}
}
21 changes: 21 additions & 0 deletions src/lib/notion/image-utils.ts
@@ -0,0 +1,21 @@
// eslint-disable-next-line @typescript-eslint/no-var-requires
const sizeOf = require('image-size')

export const fetchImageAsBlob = async (url: string) => {
try {
return await fetch(url).then(res => res.blob())
} catch (err) {
return null
}
}

export const getImageSize = async (blob: Blob) => {
if (!blob) {
return
}

const binary = (await blob.arrayBuffer()) as Uint8Array
const buffer = Buffer.from(binary)

return sizeOf(buffer)
}
2 changes: 2 additions & 0 deletions src/lib/notion/interfaces.ts
Expand Up @@ -30,6 +30,8 @@ export interface Image {
Type: string
File?: File
External?: External
Width?: number
Height?: number
}

export interface File {
Expand Down
6 changes: 1 addition & 5 deletions src/styles/global.css
Expand Up @@ -199,16 +199,12 @@ pre.dark[class*='language-'] {
}

figure {
margin: 0;
font-size: 0.85rem;
color: #999;
line-height: 1.8rem;
}

figure {
font-size: 0.85rem;
color: #999;
}

a {
color: var(--accents-1);
text-decoration: none;
Expand Down
7 changes: 3 additions & 4 deletions src/styles/notion-block.module.css
Expand Up @@ -9,12 +9,11 @@

.image {
padding: 1rem 0;
text-align: center;
width: 90%;
margin: 0 auto;
}
.image > div:first-child {
position: relative;
width: 90%;
height: 360px;
text-align: center;
}

.code {
Expand Down
16 changes: 15 additions & 1 deletion yarn.lock
Expand Up @@ -3494,6 +3494,13 @@ ignore@^5.1.8, ignore@^5.2.0:
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a"
integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==

image-size@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/image-size/-/image-size-1.0.1.tgz#86d6cfc2b1d19eab5d2b368d4b9194d9e48541c5"
integrity sha512-VAwkvNSNGClRw9mDHhc5Efax8PLlsOGcUTh0T/LIriC8vPA3U5PdqXWqkz406MoYHMKW8Uf9gWr05T/rYB44kQ==
dependencies:
queue "6.0.2"

import-fresh@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546"
Expand Down Expand Up @@ -3541,7 +3548,7 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"

inherits@2, inherits@^2.0.4:
inherits@2, inherits@^2.0.4, inherits@~2.0.3:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
Expand Down Expand Up @@ -5162,6 +5169,13 @@ punycode@^2.1.0, punycode@^2.1.1:
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==

queue@6.0.2:
version "6.0.2"
resolved "https://registry.yarnpkg.com/queue/-/queue-6.0.2.tgz#b91525283e2315c7553d2efa18d83e76432fed65"
integrity sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==
dependencies:
inherits "~2.0.3"

react-dom@^17.0.2:
version "17.0.2"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23"
Expand Down