@@ -3,8 +3,14 @@ import FileType, { FileTypeResult } from "file-type";
3
3
import fetch from "node-fetch" ;
4
4
import * as Path from "path" ;
5
5
import { makeImagePersistencePlan } from "./MakeImagePersistencePlan" ;
6
- import { logDebug , verbose , info } from "./log" ;
7
- import { ListBlockChildrenResponse } from "@notionhq/client/build/src/api-endpoints" ;
6
+ import { warning , logDebug , verbose , info } from "./log" ;
7
+ import { ListBlockChildrenResponseResult } from "notion-to-md/build/types" ;
8
+
9
+ // We several things here:
10
+ // 1) copy images locally instead of leaving them in Notion
11
+ // 2) change the links to point here
12
+ // 3) read the caption and if there are localized images, get those too
13
+ // 4) prepare for localized documents, which need a copy of every image
8
14
9
15
let existingImagesNotSeenYetInPull : string [ ] = [ ] ;
10
16
let imageOutputPath = "" ; // default to putting in the same directory as the document referring to it.
@@ -59,22 +65,65 @@ export async function initImageHandling(
59
65
}
60
66
}
61
67
62
- export async function outputImages (
63
- blocks : (
64
- | ListBlockChildrenResponse
65
- | /* not avail in types: BlockObjectResponse so we use any*/ any
66
- ) [ ] ,
68
+ // This is a "custom transformer" function passed to notion-to-markdown
69
+ // eslint-disable-next-line @typescript-eslint/require-await
70
+ export async function markdownToMDImageTransformer (
71
+ block : ListBlockChildrenResponseResult ,
67
72
fullPathToDirectoryContainingMarkdown : string ,
68
73
relativePathToThisPage : string
74
+ ) : Promise < string > {
75
+ const image = ( block as any ) . image ;
76
+
77
+ await processImageBlock (
78
+ image ,
79
+ fullPathToDirectoryContainingMarkdown ,
80
+ relativePathToThisPage
81
+ ) ;
82
+
83
+ // just concatenate the caption text parts together
84
+ const altText : string = image . caption
85
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
86
+ . map ( ( item : any ) => item . plain_text )
87
+ . join ( "" ) ;
88
+
89
+ const href : string =
90
+ image . type === "external" ? image . external . url : image . file . url ;
91
+ return `` ;
92
+ }
93
+
94
+ async function processImageBlock (
95
+ imageBlock : any ,
96
+ pathToParentDocument : string ,
97
+ relativePathToThisPage : string
69
98
) : Promise < void > {
70
- for ( const b of blocks ) {
71
- if ( "image" in b ) {
72
- await processImageBlock (
73
- b ,
74
- fullPathToDirectoryContainingMarkdown ,
75
- relativePathToThisPage
76
- ) ;
77
- }
99
+ logDebug ( "processImageBlock" , JSON . stringify ( imageBlock ) ) ;
100
+
101
+ // this is broken into all these steps to facilitate unit testing without IO
102
+ const imageSet = parseImageBlock ( imageBlock ) ;
103
+ imageSet . pathToParentDocument = pathToParentDocument ;
104
+ imageSet . relativePathToParentDocument = relativePathToThisPage ;
105
+
106
+ await readPrimaryImage ( imageSet ) ;
107
+ makeImagePersistencePlan ( imageSet , imageOutputPath , imagePrefix ) ;
108
+ await saveImage ( imageSet ) ;
109
+
110
+ // change the src to point to our copy of the image
111
+ if ( "file" in imageBlock ) {
112
+ imageBlock . file . url = imageSet . filePathToUseInMarkdown ;
113
+ } else {
114
+ imageBlock . external . url = imageSet . filePathToUseInMarkdown ;
115
+ }
116
+ // put back the simplified caption, stripped of the meta information
117
+ if ( imageSet . caption ) {
118
+ imageBlock . caption = [
119
+ {
120
+ type : "text" ,
121
+ text : { content : imageSet . caption , link : null } ,
122
+ plain_text : imageSet . caption ,
123
+ } ,
124
+ ] ;
125
+ } else {
126
+ imageBlock . caption = [ ] ;
78
127
}
79
128
}
80
129
@@ -127,20 +176,20 @@ function writeImageIfNew(path: string, buffer: Buffer) {
127
176
fs . createWriteStream ( path ) . write ( buffer ) ; // async but we're not waiting
128
177
}
129
178
130
- export function parseImageBlock ( b : any ) : ImageSet {
179
+ export function parseImageBlock ( image : any ) : ImageSet {
131
180
const imageSet : ImageSet = {
132
181
primaryUrl : "" ,
133
182
caption : "" ,
134
183
localizedUrls : locales . map ( l => ( { iso632Code : l , url : "" } ) ) ,
135
184
} ;
136
185
137
- if ( "file" in b . image ) {
138
- imageSet . primaryUrl = b . image . file . url ; // image saved on notion (actually AWS)
186
+ if ( "file" in image ) {
187
+ imageSet . primaryUrl = image . file . url ; // image saved on notion (actually AWS)
139
188
} else {
140
- imageSet . primaryUrl = b . image . external . url ; // image still pointing somewhere else. I've see this happen when copying a Google Doc into Notion. Notion kep pointing at the google doc.
189
+ imageSet . primaryUrl = image . external . url ; // image still pointing somewhere else. I've see this happen when copying a Google Doc into Notion. Notion kep pointing at the google doc.
141
190
}
142
191
143
- const mergedCaption : string = b . image . caption
192
+ const mergedCaption : string = image . caption
144
193
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
145
194
. map ( ( c : any ) => c . plain_text )
146
195
. join ( "" ) ;
@@ -169,44 +218,6 @@ export function parseImageBlock(b: any): ImageSet {
169
218
return imageSet ;
170
219
}
171
220
172
- // Download the image if we don't have it, give it a good name, and
173
- // change the src to point to our copy of the image.
174
- async function processImageBlock (
175
- b : any ,
176
- pathToParentDocument : string ,
177
- relativePathToThisPage : string
178
- ) : Promise < void > {
179
- logDebug ( "processImageBlock" , JSON . stringify ( b ) ) ;
180
-
181
- // this is broken into all these steps to facilitate unit testing without IO
182
- const imageSet = parseImageBlock ( b ) ;
183
- imageSet . pathToParentDocument = pathToParentDocument ;
184
- imageSet . relativePathToParentDocument = relativePathToThisPage ;
185
-
186
- await readPrimaryImage ( imageSet ) ;
187
- makeImagePersistencePlan ( imageSet , imageOutputPath , imagePrefix ) ;
188
- await saveImage ( imageSet ) ;
189
-
190
- // change the src to point to our copy of the image
191
- if ( "file" in b . image ) {
192
- b . image . file . url = imageSet . filePathToUseInMarkdown ;
193
- } else {
194
- b . image . external . url = imageSet . filePathToUseInMarkdown ;
195
- }
196
- // put back the simplified caption, stripped of the meta information
197
- if ( imageSet . caption ) {
198
- b . image . caption = [
199
- {
200
- type : "text" ,
201
- text : { content : imageSet . caption , link : null } ,
202
- plain_text : imageSet . caption ,
203
- } ,
204
- ] ;
205
- } else {
206
- b . image . caption = [ ] ;
207
- }
208
- }
209
-
210
221
function imageWasSeen ( path : string ) {
211
222
existingImagesNotSeenYetInPull = existingImagesNotSeenYetInPull . filter (
212
223
p => p !== path
0 commit comments