274 lines
6.8 KiB
TypeScript
274 lines
6.8 KiB
TypeScript
import { Client } from '@notionhq/client';
|
|
import {
|
|
createWriteStream,
|
|
existsSync,
|
|
mkdirSync,
|
|
writeFileSync,
|
|
} from 'node:fs';
|
|
import { get } from 'node:https';
|
|
import { dirname } from 'node:path';
|
|
import { pipeline } from 'node:stream/promises';
|
|
import { slugify } from '../../nx-dev/feature-package-schema-viewer/src/lib/slugify.utils';
|
|
const notion = new Client({ auth: process.env.NOTION_KEY });
|
|
|
|
// Instructions to run located here: https://www.notion.so/nxnrwl/17c69f3c238780eb8ef6df32ce48f919?v=db53d7de0cc94f4ab9dfce8e3654f7dc
|
|
|
|
const BLOG_ROOT = './docs/blog';
|
|
|
|
interface RichTextProperty {
|
|
type: 'rich_text';
|
|
rich_text: RichTextItem[];
|
|
}
|
|
interface RichTextItem {
|
|
type: 'text';
|
|
text: {
|
|
content: string;
|
|
link?: string;
|
|
};
|
|
annotations: {
|
|
bold: boolean;
|
|
italic: boolean;
|
|
strikethrough: boolean;
|
|
underline: boolean;
|
|
code: boolean;
|
|
color: 'default' | string;
|
|
};
|
|
plain_text: string;
|
|
href?: string;
|
|
}
|
|
interface DateProperty {
|
|
type: 'date';
|
|
date: { start: string; end?: string; time_zone?: string };
|
|
}
|
|
interface UrlProperty {
|
|
type: 'url';
|
|
url: string;
|
|
}
|
|
interface FilesProperty {
|
|
type: 'files';
|
|
files: {
|
|
name: string;
|
|
type: 'file';
|
|
file: {
|
|
url: string;
|
|
expiry_time: string;
|
|
};
|
|
}[];
|
|
}
|
|
interface SelectProperty {
|
|
type: 'select';
|
|
select: { id: string; name: string; color: string };
|
|
}
|
|
interface TitleProperty {
|
|
type: 'title';
|
|
title: RichTextItem[];
|
|
}
|
|
|
|
interface WebinarResponse {
|
|
Description: RichTextProperty;
|
|
Date: DateProperty;
|
|
['YouTube Link']: UrlProperty;
|
|
['Webinar Card Image']: FilesProperty;
|
|
Status: SelectProperty;
|
|
['Speaker(s)']: RichTextProperty;
|
|
Time: RichTextProperty;
|
|
['Link to Landing Page']: UrlProperty;
|
|
Title: TitleProperty;
|
|
}
|
|
interface ProcessedWebinar {
|
|
Description: string;
|
|
Date: string;
|
|
['YouTube Link']: string;
|
|
['Webinar Card Image']: string[];
|
|
Status: string;
|
|
['Speaker(s)']: RichTextProperty;
|
|
Time: RichTextProperty;
|
|
['Link to Landing Page']: UrlProperty;
|
|
Title: TitleProperty;
|
|
}
|
|
|
|
const propertyParsers = {
|
|
rich_text: (prop: RichTextProperty): string => {
|
|
return prop.rich_text
|
|
.map((item) => {
|
|
let text = item.text.content;
|
|
if (item.annotations.bold) {
|
|
text = `**${text}**`;
|
|
} else if (item.annotations.code) {
|
|
text = `\`${text}\``;
|
|
} else if (item.annotations.italic) {
|
|
text = `*${text}*`;
|
|
} else if (item.annotations.strikethrough) {
|
|
text = `~${text}~`;
|
|
} else if (item.annotations.underline) {
|
|
text = `_${text}_`;
|
|
}
|
|
if (item.href) {
|
|
text = `[${text}](${item.href})`;
|
|
}
|
|
return text;
|
|
})
|
|
.join('');
|
|
},
|
|
select: (prop: SelectProperty): string => {
|
|
return prop.select.name;
|
|
},
|
|
title: (prop: TitleProperty): string => {
|
|
return propertyParsers.rich_text({
|
|
type: 'rich_text',
|
|
rich_text: prop.title,
|
|
});
|
|
},
|
|
url: (prop: UrlProperty): string => {
|
|
return prop.url;
|
|
},
|
|
date: (prop: DateProperty): string => {
|
|
return prop.date.start;
|
|
},
|
|
files: (prop: FilesProperty): string => {
|
|
return prop.files.map((entry) => {
|
|
return entry.file.url;
|
|
})[0];
|
|
},
|
|
};
|
|
|
|
async function main() {
|
|
const response = await notion.databases.query({
|
|
database_id: '17c69f3c238780eb8ef6df32ce48f919',
|
|
});
|
|
response.results.forEach(async (entry: any) => {
|
|
const webinar: WebinarResponse = entry.properties;
|
|
const processedWebinar = Object.fromEntries(
|
|
Object.entries(webinar).map(([key, val]) => {
|
|
return [key, propertyParsers[val.type](val)];
|
|
})
|
|
);
|
|
|
|
let cover_image = '';
|
|
const imageFiles = webinar['Webinar Card Image'].files;
|
|
function ensureDirectoryExistence(filePath) {
|
|
var directory = dirname(filePath);
|
|
if (existsSync(directory)) {
|
|
return true;
|
|
}
|
|
ensureDirectoryExistence(directory);
|
|
mkdirSync(directory);
|
|
}
|
|
async function download(url: string, path: string) {
|
|
return new Promise(async (onSuccess) => {
|
|
get(url, async (res) => {
|
|
ensureDirectoryExistence(path);
|
|
const fileWriteStream = createWriteStream(path, {
|
|
autoClose: true,
|
|
flags: 'w',
|
|
});
|
|
await pipeline(res, fileWriteStream);
|
|
onSuccess('success');
|
|
});
|
|
});
|
|
}
|
|
if (imageFiles.length > 0) {
|
|
download(
|
|
imageFiles[0].file.url,
|
|
BLOG_ROOT +
|
|
`/images/${webinar.Date.date.start}/${imageFiles[0].name.replaceAll(
|
|
' ',
|
|
'-'
|
|
)}`
|
|
);
|
|
console.log(
|
|
'Downloaded image',
|
|
BLOG_ROOT +
|
|
`/images/${webinar.Date.date.start}/${imageFiles[0].name.replaceAll(
|
|
' ',
|
|
'-'
|
|
)}`
|
|
);
|
|
cover_image = `/blog/images/${
|
|
webinar.Date.date.start
|
|
}/${imageFiles[0].name.replaceAll(' ', '-')}`;
|
|
}
|
|
|
|
const webinarMarkdown = `---
|
|
title: "${processedWebinar.Title}"
|
|
description: "${processedWebinar.Description}"
|
|
slug: '${slugify(processedWebinar.Title)}'
|
|
authors: [${processedWebinar['Speaker(s)']
|
|
.replace(', and ', ', ')
|
|
.split(', ')
|
|
.map((author) => `'${author}'`)
|
|
.join(', ')}]
|
|
tags: [webinar]${
|
|
cover_image
|
|
? `
|
|
cover_image: ${cover_image}`
|
|
: ''
|
|
}${
|
|
processedWebinar['Time']
|
|
? `
|
|
time: ${processedWebinar['Time']}`
|
|
: ''
|
|
}${
|
|
processedWebinar['Status']
|
|
? `
|
|
status: ${processedWebinar['Status']}`
|
|
: ''
|
|
}${
|
|
processedWebinar['YouTube Link'] &&
|
|
processedWebinar['Status'] === 'Past - Ungated'
|
|
? `
|
|
youtubeUrl: ${processedWebinar['YouTube Link']}`
|
|
: ''
|
|
}${
|
|
processedWebinar['Link to Landing Page']
|
|
? `
|
|
registrationUrl: ${processedWebinar['Link to Landing Page']}`
|
|
: ''
|
|
}
|
|
---
|
|
|
|
${
|
|
processedWebinar.Time
|
|
? `**${new Date(
|
|
processedWebinar.Date + ' ' + new Date().toTimeString()
|
|
).toLocaleDateString('en-US', {
|
|
month: 'short',
|
|
day: '2-digit',
|
|
year: 'numeric',
|
|
})} - ${processedWebinar.Time}**`
|
|
: ''
|
|
}
|
|
|
|
${
|
|
processedWebinar['Speaker(s)']
|
|
? `Presented by ${processedWebinar['Speaker(s)']}`
|
|
: ''
|
|
}
|
|
|
|
${processedWebinar.Description}
|
|
|
|
${
|
|
processedWebinar.Status === 'Upcoming'
|
|
? `{% call-to-action title="Register today!" url="${processedWebinar['Link to Landing Page']}" description="Save your spot" /%}`
|
|
: ''
|
|
}${
|
|
processedWebinar.Status === 'Past - Gated' &&
|
|
processedWebinar['Link to Landing Page']
|
|
? `{% call-to-action title="Download the recording" url="${processedWebinar['Link to Landing Page']}" description="Sign up to gain access" /%}`
|
|
: ''
|
|
}
|
|
`;
|
|
|
|
writeFileSync(
|
|
BLOG_ROOT +
|
|
'/' +
|
|
processedWebinar.Date +
|
|
'-' +
|
|
slugify(processedWebinar.Title) +
|
|
'.md',
|
|
webinarMarkdown
|
|
);
|
|
});
|
|
}
|
|
main();
|