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:
parent
e0b5ab31b4
commit
0d9ecfd8f5
2 changed files with 412 additions and 398 deletions
93
functions.js
93
functions.js
|
@ -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
|
||||
}
|
||||
|
|
19
index.js
19
index.js
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue