Make Seance into separate Object

Now, the Seance object is what everyone operates with. That way,
we can do fancy stuff like emitting events, etc. if the need so
arises (as it will, very soon; trust me).
This commit is contained in:
Badri Sunderarajan 2020-05-04 17:55:41 +05:30
parent e0b5ab31b4
commit 0d9ecfd8f5
2 changed files with 412 additions and 398 deletions

View file

@ -11,10 +11,12 @@ const Rembrandt = require('rembrandt')
const config = require('./config')
const MEDIUM_IMG_CDN = 'https://miro.medium.com/fit/c/'
class Seance {
constructor(...args) {
this.MEDIUM_IMG_CDN = 'https://miro.medium.com/fit/c/'
try {
const ghostAdmin = new GhostAdminAPI({
this.ghostAdmin = new GhostAdminAPI({
url: config.ghost.url,
version: config.ghost.version,
key: config.ghost.admin_key,
@ -22,19 +24,26 @@ try {
} catch(err) {
console.error('Your Ghost isn\'t configured. Please run `seance setup` to fix this!')
}
/**
* function [fetchFromMedium]
* @returns [string] status
*/
}
const fetchFromMedium = async (mediumUrl) => {
async fetchFromMedium (mediumUrl) {
console.info(`Fetching: ${mediumUrl}`);
output = path.join(process.env.PWD, 'content')
var output = path.join(process.env.PWD, 'content')
var json
json = await this.fetchMediumJSON(mediumUrl)
// use mediumexporter's getPost function to fetch a Medium post
const post = await getPost(mediumUrl, {
returnObject: true,
output: output,
postJSON: json
}).catch((err) => {
return {
error: err,
@ -43,7 +52,7 @@ const fetchFromMedium = async (mediumUrl) => {
// set output folder path
// this is based on what mediumexporter chooses as the output folder
outputFolder = path.join(output, post.slug)
var outputFolder = path.join(output, post.slug)
console.info(`Saving to: ${outputFolder}`)
@ -80,15 +89,16 @@ const fetchFromMedium = async (mediumUrl) => {
return post
};
/**
* function [pushToGhost]
* @returns [string] status
*/
const pushToGhost = async (postSlug) => {
async pushToGhost (postSlug) {
console.info('Pushing: ' + postSlug);
// Decide working path
postFolder = path.resolve('content/' + postSlug)
var postFolder = path.resolve('content/' + postSlug)
// Verify file exists
if (!fs.existsSync(postFolder)) {
@ -107,7 +117,7 @@ const pushToGhost = async (postSlug) => {
}
// Decide WebDAV upload path
current_date = new Date()
var current_date = new Date()
const uploadPath = path.join(
current_date.getUTCFullYear().toString(),
@ -125,7 +135,7 @@ const pushToGhost = async (postSlug) => {
// load metadata file
console.debug('Loading metadata')
postMetaFile = path.join(postFolder, 'metadata.json')
var postMetaFile = path.join(postFolder, 'metadata.json')
let postMeta = await JSON.parse(fs.readFileSync(postMetaFile))
// Process lines
@ -167,14 +177,14 @@ const pushToGhost = async (postSlug) => {
console.warn('Skipping missing image: ' + imageName)
} else {
// check for separator image
var isScissors = await checkScissors(imagePath)
var isScissors = await this.checkScissors(imagePath)
if (isScissors) {
newLine = '\n---\n'
} else {
// upload pic to server
console.debug(`Adding to upload queue: ${imageName}`)
uploadedImages.push(imageName)
uploadDav(davPath, imagePath)
this.uploadDav(davPath, imagePath)
newLine = '![' + imageAlt + '](' + uploadedPath + '/' + imageName + ')'
}
@ -201,7 +211,7 @@ const pushToGhost = async (postSlug) => {
console.warn(`Skipping feature image "${imageName}": file not found`)
} else {
console.log(`Uploading feature image: ${imageName}`)
uploadDav(davPath, imagePath)
this.uploadDav(davPath, imagePath)
featuredImagePath = uploadedPath + '/' + imageName
}
}
@ -217,12 +227,12 @@ const pushToGhost = async (postSlug) => {
// Uploads will continue in paralell though
console.debug('Adding to Ghost')
ghostAdmin.posts.add({
this.ghostAdmin.posts.add({
title: postMeta.title,
custom_excerpt: postMeta.subtitle || null,
tags: postMeta.tags,
authors: users,
html: markdown.toHTML(fs.readFileSync(postOutput, mode='utf-8')),
html: markdown.toHTML(fs.readFileSync(postOutput, 'utf-8')),
feature_image: featuredImagePath
}, {source: 'html'})
.then((res) => {
@ -234,20 +244,32 @@ const pushToGhost = async (postSlug) => {
})
};
/**
* function [mediumToGhost]
* @returns [string] status
*/
const mediumToGhost = (mediumUrl) => {
mediumToGhost (mediumUrl) {
console.info('Copying: ' + mediumUrl);
};
}
async function fetchMediumJSON(mediumUrl) {
console.debug(`Fetching: ${mediumUrl}`)
async fetchMediumJSON(mediumUrl) {
var json
var text
if (mediumUrl.match(/^http/i)) {
// add ?json attribute
mediumUrl = mediumUrl.replace(/#.*$/, '')
mediumUrl= `${mediumUrl}?format=json`
const response = await fetch(mediumUrl)
const text = await response.text()
const json = await JSON.parse(text.substr(text.indexOf('{')))
text = await response.text()
} else {
throw { error: 'URL must be a Medium URL' }
}
json = await JSON.parse(text.substr(text.indexOf('{')))
return json;
}
@ -256,7 +278,7 @@ async function fetchMediumJSON(mediumUrl) {
* @returns [boolean] matchStatus
*/
const checkScissors = async (imagePath) => {
async checkScissors (imagePath) {
// Decide "separator" image
// If set, images matching this will be ignored and replaced
// with a horizontal-rule ("---" in markdown) instead.
@ -290,7 +312,7 @@ const checkScissors = async (imagePath) => {
* function [createUser]
* @returns [object] ghost data json
*/
const generateUserData = async (mediumUsername, email) => {
async generateUserData (mediumUsername, email) {
console.debug('Creating: @' + mediumUsername + '(email: ' + email + ')');
const mediumUrl = `https://medium.com/@${mediumUsername}/?format=json`;
const json = await fetchMediumJSON(mediumUrl);
@ -320,7 +342,7 @@ const generateUserData = async (mediumUsername, email) => {
console.log("Uploading to server")
await uploadDav(path.join(config.webdav.path_prefix,'avatars'),
await this.uploadDav(path.join(config.webdav.path_prefix,'avatars'),
filePath)
// Generate Ghost JSON
@ -347,7 +369,7 @@ const generateUserData = async (mediumUsername, email) => {
return(JSON.stringify(ghostData))
};
const createDirIfNotExist = async (client, folder) => {
async createDirIfNotExist (client, folder) {
// recursively create subfolders if they don't exist.
//safety: don't touch directories outside WEBDAV_PATH_PREFIX
@ -370,7 +392,7 @@ const createDirIfNotExist = async (client, folder) => {
console.debug(`Noting missing subdirectory: ${folder}`)
// first, create the parent directory (if required)
if (!await createDirIfNotExist(client, path.dirname(folder))) {
if (!await this.createDirIfNotExist(client, path.dirname(folder))) {
// if not created, we fail too :-/
return false
}
@ -409,10 +431,10 @@ const createDirIfNotExist = async (client, folder) => {
* function [uploadDav]
* @returns [string] status
*/
const uploadDav = async (dirPath, filePath) => {
async uploadDav (dirPath, filePath) {
// connect to webdav
client = createClient(
const client = createClient(
config.webdav.server_url,
{
username: config.webdav.username,
@ -422,29 +444,26 @@ const uploadDav = async (dirPath, filePath) => {
// create directory if not exists
console.debug(`[dav-upload] Loading ${dirPath}`)
if (!await createDirIfNotExist(client, dirPath)) {
if (!await this.createDirIfNotExist(client, dirPath)) {
console.error(`[dav-upload] Could not upload ${path.basename(filePath)} :(`)
return false
}
// upload a file
console.debug('Uploading file')
outStream = client.createWriteStream(
const outStream = client.createWriteStream(
path.join(dirPath, path.basename(filePath))
)
outStream.on('finish', () => console.debug('Uploaded successfully.'))
inStream = fs.createReadStream(filePath)
const inStream = fs.createReadStream(filePath)
.pipe(outStream)
return true
}
module.exports = {
fetchFromMedium,
pushToGhost,
mediumToGhost,
generateUserData,
checkScissors,
uploadDav
}
module.exports = {
Seance
}

View file

@ -11,12 +11,7 @@ const yaml = require('js-yaml')
const config = require('./config')
const {
fetchFromMedium,
pushToGhost,
mediumToGhost,
generateUserData,
checkScissors,
uploadDav,
Seance,
} = require ('./functions')
program
@ -120,7 +115,7 @@ program.command('fetch-medium <post_url>')
.alias('fetch')
.description('fetch a Medium post')
.action((post_url) => {
fetchFromMedium(post_url)
new Seance().fetchFromMedium(post_url)
.then((post) => {
console.info(`"${post.title}" fetched successfully.`)
})
@ -130,20 +125,20 @@ program.command('push-ghost <file>')
.alias('push')
.description('push a downloaded Medium post to Ghost')
.action((file) => {
pushToGhost(file);
new Seance().pushToGhost(file);
});
program.command('medium-to-ghost <mediumUrl>')
.alias('import')
.description('copy a Medium file over to Ghost')
.action((mediumUrl) => {
pushToGhost(mediumUrl);
new Seance().pushToGhost(mediumUrl);
});
program.command('create-user <username> <email>')
.description('create ghost-import.json to import Medium user to Ghost')
.action(async (username, email) => {
const jsonOut = await generateUserData(username, email)
const jsonOut = await new Seance().generateUserData(username, email)
.catch((err) => {
console.log(`Error: ${err.error}`)
return
@ -162,13 +157,13 @@ program.command('webdav-test <file>')
current_date.getUTCMonth().toString(),
'test' // TODO: replace with article slug
)
uploadDav(dir_path, file);
new Seance().uploadDav(dir_path, file);
});
program.command('check-scissors <file>')
.description('[test command] check if an image matches the set separator')
.action(async (file) => {
console.log(await checkScissors(file))
console.log(await new Seance().checkScissors(file))
})
program.parse(process.argv)