ae1aacd17c
Now, instead of having to host Seance right at example.com, you can also host it underneath at example.com/seance by changing the appropriate setting!
259 lines
8.7 KiB
JavaScript
Executable file
259 lines
8.7 KiB
JavaScript
Executable file
#! /usr/bin/env node
|
|
|
|
const program = require('commander')
|
|
const path = require('path')
|
|
const prompt = require('prompt-async')
|
|
const readline = require('readline')
|
|
const os = require('os')
|
|
const fs = require('fs')
|
|
const yaml = require('js-yaml')
|
|
|
|
const config = require('./config')
|
|
|
|
const {
|
|
Seance,
|
|
} = require ('./seance')
|
|
|
|
|
|
// Set up Seance CLI notifications
|
|
const seance = new Seance()
|
|
|
|
seance.on('update', (e) => {
|
|
console.log(e.message)
|
|
})
|
|
|
|
seance.on('notification', (e) => {
|
|
console.warn(e.message)
|
|
})
|
|
|
|
seance.on('error', (e) => {
|
|
console.error(e.message)
|
|
})
|
|
|
|
program
|
|
.version('1.0.0-dev')
|
|
.description('pull posts from Medium and add them to a Ghost blog');
|
|
|
|
program.command('setup')
|
|
.description('Initial setup and configuration')
|
|
.action(async () => {
|
|
console.log('Hello and welcome to Seance.')
|
|
console.log(
|
|
'\n\nWe\'re going to take you through some steps' +
|
|
' to set up your system.\n'
|
|
)
|
|
|
|
var res
|
|
prompt.start()
|
|
|
|
console.log('First up: File uploads.')
|
|
console.log(
|
|
'Would you like to upload your files via WebDAV, or just ' +
|
|
'copy them to a local folder on your filesystem? Type ' +
|
|
'"webdav" or "local" to choose.\n'
|
|
)
|
|
|
|
res = await prompt.get([
|
|
{
|
|
name: 'upload_mode',
|
|
default: 'webdav',
|
|
pattern: /^(webdav|local)$/ig,
|
|
message: 'Please enter "webdav" or "local"',
|
|
},
|
|
])
|
|
|
|
if (res.upload_mode == 'webdav') {
|
|
|
|
console.log('You\'re going with WebDAV? Awesome!')
|
|
console.log(
|
|
'Please enter your server url (including the port), ' +
|
|
'username, and password\n'
|
|
)
|
|
|
|
res = await prompt.get([
|
|
{ name: 'server_url', default: config.webdav.server_url || '' },
|
|
{ name: 'username', default: config.webdav.username || '' },
|
|
{ name: 'password', default: config.webdav.password || '' , hidden: true},
|
|
])
|
|
config.webdav.server_url = res.server_url
|
|
config.webdav.username = res.username
|
|
config.webdav.password = res.password
|
|
console.log(`\nOkay. So we have ${config.webdav.username} on ${config.webdav.server_url} with [ the password you set]`)
|
|
|
|
console.log(
|
|
'\nA couple more settings for your WebDAV: ' +
|
|
'we need to know the path prefix and the uploaded path prefix.\n' +
|
|
'The path prefix is the subfolder to which you upload, like ' +
|
|
'`/seance-uploads`, while the uploaded path prefix is what '+
|
|
'you\'d stick in front of the filename after uploading ' +
|
|
'(like `https://media.mysite.com/seance-uploads`).\n'
|
|
)
|
|
res = await prompt.get([
|
|
{ name: 'path_prefix', default: config.webdav.path_prefix || '' },
|
|
{
|
|
name: 'uploaded_path_prefix',
|
|
default: config.uploaded_path_prefix || config.webdav.uploaded_path_prefix || ''
|
|
},
|
|
])
|
|
config.webdav.path_prefix = res.path_prefix
|
|
config.uploaded_path_prefix = res.uploaded_path_prefix
|
|
console.log(`Cool. So uploads to ${config.webdav.path_prefix} will be visible at ${config.uploaded_path_prefix}.`)
|
|
|
|
} else if (res.upload_mode == 'local') {
|
|
console.log('You\'re saving files locally? Smart!')
|
|
console.log(
|
|
'Two settings we need to know to get things running ' +
|
|
'smoothly: we need the local path/folder where you\'ll be ' +
|
|
'uploading the files, and the uploaded path prefix.\n' +
|
|
'The local path is the folder to which you upload, like ' +
|
|
'`/var/www/seance-uploads`, while the uploaded path prefix ' +
|
|
'is what you\'d stick in front of the filename after ' +
|
|
'uploading (like `https://media.mysite.com/seance-uploads`).\n'
|
|
)
|
|
res = await prompt.get([
|
|
{ name: 'path_prefix', default: config.local_upload.path_prefix || '' },
|
|
{ name: 'uploaded_path_prefix', default: config.uploaded_path_prefix || '' },
|
|
])
|
|
config.local_upload.path_prefix = res.path_prefix
|
|
config.uploaded_path_prefix = res.uploaded_path_prefix
|
|
console.log(`Cool. So uploads to ${config.local_upload.path_prefix} will be visible at ${config.uploaded_path_prefix}.`)
|
|
}
|
|
|
|
console.log('\n\nNext up: Ghost settings.')
|
|
console.log(
|
|
'The Ghost URL is basically the link to your main ' +
|
|
'Ghost site, and the admin API key can be found by going to ' +
|
|
'your Settings -> Integrations page.\n'
|
|
)
|
|
|
|
res = await prompt.get([
|
|
{ name: 'url', default: config.ghost.url || '' },
|
|
{ name: 'version', default: config.ghost.version || 'v2' },
|
|
{ name: 'admin_key', default: config.ghost.admin_key || '' },
|
|
])
|
|
config.ghost.url = res.url
|
|
config.ghost.version = res.version
|
|
config.ghost.admin_key = res.admin_key
|
|
console.log(`Right. So that's Ghost ${config.ghost.version} running at ${config.ghost.url} with key ${config.ghost.admin_key}`)
|
|
|
|
console.log('\n\nNow, a bit about the server.')
|
|
console.log(
|
|
'This server usually runs on the main path (eg. example.com/).' +
|
|
'If you want to host seance on a different subpath (eg. ' +
|
|
'example.com/seance) then please enter that last part of the' +
|
|
'string now (eg. /seance).'
|
|
)
|
|
res = await prompt.get([
|
|
{ name: 'base_path', default: config.basePath || '/' },
|
|
])
|
|
if (res.base_path == '/') {
|
|
console.log('Okay. Serving on the root path then :)')
|
|
} else {
|
|
config.basePath = res.base_path
|
|
console.log(
|
|
'Right, so we\'ll be serving at yoursite.com' +
|
|
`${config.basePath} then :)`
|
|
)
|
|
}
|
|
|
|
console.log(
|
|
'\n\nA final thing. Do you have a "scissors" or other image ' +
|
|
'used as a separator in your article? If so, enter the path ' +
|
|
'here and we\'ll check against it to auto-convert them to ' +
|
|
'Ghost-friendly separators. If you don\'t use scissors, you ' +
|
|
'can just press Enter without typing anything.\n'
|
|
)
|
|
|
|
res = await prompt.get([
|
|
{ name: 'scissors', default: config.scissors || '' },
|
|
])
|
|
config.scissors = res.scissors
|
|
if (config.scissors) {
|
|
console.log(`Done. Scissors set to ${config.scissors}`)
|
|
} else {
|
|
console.log('No scissors? That\'s fine. You\'ll get there one day :)')
|
|
}
|
|
|
|
console.log('\n\nFinal confirmation: would you like to save these settings?')
|
|
const { save } = await prompt.get(['save'])
|
|
if (save == '' || (save[0] && save[0].toLowerCase() != 'n')) {
|
|
const configDir = path.join(os.homedir(), '.config')
|
|
if (!fs.existsSync(configDir)) {
|
|
os.makeDirSync(configDir)
|
|
}
|
|
userConfig = path.join(configDir, 'seance.yaml')
|
|
data = yaml.safeDump(config)
|
|
fs.writeFileSync(userConfig, data)
|
|
console.log('\nThat\'s it - we\'re done!')
|
|
} else {
|
|
console.log('Not saving? What a pity!')
|
|
}
|
|
})
|
|
|
|
program.command('fetch-medium <post_url>')
|
|
.alias('fetch')
|
|
.description('fetch a Medium post')
|
|
.action((post_url) => {
|
|
new Seance().fetchFromMedium(post_url)
|
|
.then((post) => {
|
|
console.info(`"${post.title}" fetched successfully.`)
|
|
})
|
|
});
|
|
|
|
program.command('push-ghost <file>')
|
|
.alias('push')
|
|
.description('push a downloaded Medium post to Ghost')
|
|
.option('-d, --dry-run', "full dry run: doesn't upload anything (same as --no-upload --no-push)")
|
|
.option('--no-upload', "partial dry run: don't upload images")
|
|
.option('--no-push', "partial dry run: don't push to ghost")
|
|
.action((file, o) => {
|
|
seance.pushToGhost(file, {
|
|
dryRun: o.dryRun,
|
|
noUpload: !o.upload,
|
|
noPush: !o.push,
|
|
})
|
|
});
|
|
|
|
program.command('medium-to-ghost <mediumUrl>')
|
|
.alias('import')
|
|
.description('copy a Medium file over to Ghost')
|
|
.action((mediumUrl) => {
|
|
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 seance.generateUserData(username, email)
|
|
.catch((err) => {
|
|
console.log(`Error: ${err.error}`)
|
|
return
|
|
})
|
|
|
|
const userSlug = JSON.parse(jsonOut).data.users[0].slug
|
|
const outFile = `user-${userSlug}.json`
|
|
await fs.promises.writeFile(outFile, jsonOut, 'utf-8')
|
|
console.log(`Saved to ${outFile}`);
|
|
});
|
|
|
|
program.command('webdav-test <file>')
|
|
.description('[test command] upload stuff to WebDAV')
|
|
.action(async (file) => {
|
|
// decide path
|
|
current_date = new Date();
|
|
var dir_path = path.join(
|
|
config.webdav.path_prefix,
|
|
current_date.getUTCFullYear().toString(),
|
|
current_date.getUTCMonth().toString(),
|
|
'test' // TODO: replace with article slug
|
|
)
|
|
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 seance.checkScissors(file))
|
|
})
|
|
|
|
program.parse(process.argv)
|