Skip to content

Instantly share code, notes, and snippets.

@elevenpassin
Created September 27, 2021 15:34
Show Gist options
  • Save elevenpassin/0f030095d4ff71a16bd1938d544e186d to your computer and use it in GitHub Desktop.
Save elevenpassin/0f030095d4ff71a16bd1938d544e186d to your computer and use it in GitHub Desktop.
All credit goes to @kentcdodds ! I just extracted the code from this [commit](https://github.com/kentcdodds/kentcdodds.com/commit/d7ebfcc7e3e8fb8354f0ca58da8159fccaeeb14d#) for personal use :D
import path from 'path'
import cloudinary from 'cloudinary'
import glob from 'glob'
import fs from 'fs'
import os from 'os'
const directoryCache = {}
const existingFolders = new Set()
cloudinary.config({
cloud_name: 'xxxxxx',
api_key: 'xxxxxx',
api_secret: 'xxxxxx',
secure: true,
})
const repoDirParentDir = path.join(os.homedir(), 'code')
const mdxFilePaths = glob.sync(
path.join(repoDirParentDir, 'kentcdodds.com/content/**/*.mdx'),
)
for (const mdxFilePath of mdxFilePaths) {
console.log('starting work on', mdxFilePath)
const content = await fs.promises.readFile(mdxFilePath, 'utf8')
const banner = content.match(/banner: '?(\.\/.*?)'?$/m)?.[1]
const metaImage = content.match(/metaImage: '?(\.\/.*?)'?$/m)?.[1]
const guestPhoto = content.match(/guestPhoto: '?(\.\/.*?)'?$/m)?.[1]
const inPostImages = (content.match(/!\[.*?\]\(\.\/(.*?)\)/g) ?? []).map(
s => s.match(/\((.*)\)/)[1],
)
const images = [banner, metaImage, guestPhoto, ...inPostImages]
.filter(Boolean)
.map(image => ({
relativePath: image,
fullPath: path.join(path.dirname(mdxFilePath), image),
}))
if (!images.length) continue
const cloudinaryFolder = mdxFilePath
.replace(`${repoDirParentDir}/`, '')
.replace('/index.mdx', '')
const foldersToCreate = new Set()
for (const image of images) {
const cloudinaryParentPath = getCloudinaryParentPath(
cloudinaryFolder,
image.relativePath,
)
foldersToCreate.add(cloudinaryParentPath)
}
await Promise.all(
Array.from(foldersToCreate).map(async folderToCreate => {
if (!existingFolders.has(folderToCreate))
await createFolder(folderToCreate)
}),
)
const uploadedImages = await Promise.all(
images.map(async image => {
const cloudinaryParentPath = getCloudinaryParentPath(
cloudinaryFolder,
image.relativePath,
)
const uploadedImage = await uploadFile(
image.fullPath,
cloudinaryParentPath,
)
return {
...image,
url: uploadedImage.secure_url,
}
}),
)
let newContent = content
for (const image of uploadedImages) {
newContent = newContent.replace(image.relativePath, image.url)
}
newContent = newContent.replace(/banner: /, 'bannerUrl: ')
await fs.promises.writeFile(mdxFilePath, newContent)
const percent = (
((mdxFilePaths.indexOf(mdxFilePath) + 1) / mdxFilePaths.length) *
100
).toFixed(2)
console.log(`${percent}% complete`)
}
function getCloudinaryParentPath(cloudinaryFolder, relativePath) {
const cloudinaryImagePath = path.join(cloudinaryFolder, relativePath)
// most images are in a /images directory and that extra nesting
// doesn't make sense on cloudinary
return path.parse(cloudinaryImagePath).dir.replace('/images', '')
}
async function createFolder(fullPath) {
const result = await cloudinary.v2.api.create_folder(fullPath)
existingFolders.add(fullPath)
return result
}
async function uploadFile(filePath, folder) {
const uploadedImage = await cloudinary.v2.uploader.upload(filePath, {
public_id: path.parse(filePath).name,
overwrite: true,
folder,
})
return uploadedImage
}
process.on('unhandledRejection', error => {
console.error(error.stack)
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment