tangled
alpha
login
or
join now
apoena.dev
/
sequoia
forked from
stevedylan.dev/sequoia
A CLI for publishing standard.site documents to ATProto
0
fork
atom
overview
issues
pulls
pipelines
feat: add blob images
Julien Calixte
1 day ago
702a1852
89253bee
+26
-37
1 changed file
expand all
collapse all
unified
split
packages
cli
src
commands
publish-lite.ts
+26
-37
packages/cli/src/commands/publish-lite.ts
···
36
36
)
37
37
}
38
38
39
39
-
async function resolveLocalImagePath(
39
39
+
function getImageCandidates(
40
40
src: string,
41
41
postFilePath: string,
42
42
contentDir: string,
43
43
imagesDir?: string,
44
44
-
): Promise<string | null> {
44
44
+
): string[] {
45
45
const candidates = [
46
46
path.resolve(path.dirname(postFilePath), src),
47
47
path.resolve(contentDir, src),
48
48
]
49
49
if (imagesDir) {
50
50
candidates.push(path.resolve(imagesDir, src))
51
51
-
// Try stripping a leading directory that matches imagesDir basename
52
51
const baseName = path.basename(imagesDir)
53
52
const idx = src.indexOf(baseName)
54
53
if (idx !== -1) {
···
56
55
candidates.push(path.resolve(imagesDir, after))
57
56
}
58
57
}
59
59
-
60
60
-
for (const candidate of candidates) {
61
61
-
try {
62
62
-
const stat = await fs.stat(candidate)
63
63
-
if (stat.isFile() && stat.size > 0) return candidate
64
64
-
} catch {}
65
65
-
}
66
66
-
return null
58
58
+
return candidates
67
59
}
68
60
69
61
async function uploadBlob(
70
62
agent: Agent,
71
71
-
filePath: string,
63
63
+
candidates: string[],
72
64
): Promise<BlobObject | undefined> {
73
73
-
if (!(await fileExists(filePath))) return undefined
65
65
+
for (const filePath of candidates) {
66
66
+
if (!(await fileExists(filePath))) continue
74
67
75
75
-
try {
76
76
-
const imageBuffer = await fs.readFile(filePath)
77
77
-
const mimeType = mimeTypes.lookup(filePath) || "application/octet-stream"
78
78
-
const response = await agent.com.atproto.repo.uploadBlob(
79
79
-
new Uint8Array(imageBuffer),
80
80
-
{ encoding: mimeType },
81
81
-
)
82
82
-
return {
83
83
-
$type: "blob",
84
84
-
ref: { $link: response.data.blob.ref.toString() },
85
85
-
mimeType,
86
86
-
size: imageBuffer.byteLength,
87
87
-
}
88
88
-
} catch (error) {
89
89
-
console.error(`Error uploading blob ${filePath}:`, error)
90
90
-
return undefined
68
68
+
try {
69
69
+
const imageBuffer = await fs.readFile(filePath)
70
70
+
if (imageBuffer.byteLength === 0) continue
71
71
+
const mimeType = mimeTypes.lookup(filePath) || "application/octet-stream"
72
72
+
const response = await agent.com.atproto.repo.uploadBlob(
73
73
+
new Uint8Array(imageBuffer),
74
74
+
{ encoding: mimeType },
75
75
+
)
76
76
+
return {
77
77
+
$type: "blob",
78
78
+
ref: { $link: response.data.blob.ref.toString() },
79
79
+
mimeType,
80
80
+
size: imageBuffer.byteLength,
81
81
+
}
82
82
+
} catch {}
91
83
}
84
84
+
return undefined
92
85
}
93
86
94
87
async function processImages(
···
111
104
const src = match[2]!
112
105
if (!isLocalPath(src)) continue
113
106
114
114
-
const resolved = await resolveLocalImagePath(
115
115
-
src, postFilePath, contentDir, imagesDir,
116
116
-
)
117
117
-
if (!resolved) continue
118
118
-
119
119
-
let blob = uploadCache.get(resolved)
107
107
+
let blob = uploadCache.get(src)
120
108
if (!blob) {
121
121
-
blob = await uploadBlob(agent, resolved)
109
109
+
const candidates = getImageCandidates(src, postFilePath, contentDir, imagesDir)
110
110
+
blob = await uploadBlob(agent, candidates)
122
111
if (!blob) continue
123
123
-
uploadCache.set(resolved, blob)
112
112
+
uploadCache.set(src, blob)
124
113
}
125
114
126
115
images.push({ image: blob, alt: alt || undefined })