Created
November 10, 2018 16:50
-
-
Save clowestab/7d5bcbdf1369d2e41b1facb97343e967 to your computer and use it in GitHub Desktop.
A script for synchronising your Instagram posts with your Ghost blog as discussed on my blog (https://thomasclowes.com)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const Parser = require('rss-parser'); | |
const request = require('request'); | |
const fs = require('fs'); | |
const mime = require('mime-types'); | |
const slugify = require('slugify'); | |
//Enter your ghost credentials here | |
const clientId = "ghost-frontend"; | |
const clientSecret = "enter-your-secret"; | |
const username = "enter-your-email"; | |
const password = "enter-your-password"; | |
//Function to query the ghost API for an access token with which to sign requests | |
const getAccessToken = function() { | |
console.log("Get Access Token Called"); | |
const tokenResponse = request | |
.post('https://thomasclowes.com/ghost/api/v0.1/authentication/token', function (e, r, body) { | |
console.log(e); | |
const parsed = JSON.parse(body); | |
const accessToken = parsed.access_token; | |
console.log(accessToken); | |
//Once we have an access token we can fetch our Instagram posts | |
getInstagramPosts(accessToken); | |
}) | |
.form({ | |
'username': username, | |
'password': password, | |
'grant_type': 'password', | |
'client_id': clientId, | |
'client_secret':clientSecret | |
}); | |
} | |
//We will hold our post objects fetched and parsed from our feed globally | |
//So we dont have to pass them around functions. This is lame. | |
let itemsArray; | |
//Function for pulling Instagram posts from my personal QueryFeed RSS Feed | |
const getInstagramPosts = function(accessToken) { | |
(async () => { | |
const feedUrl = 'https://queryfeed.net/instagram?q=thomasclowes'; | |
const feed = await parser.parseURL(feedUrl); | |
console.log("Feed Title: " + feed.title); | |
console.log("Looping through parsed Instagram posts"); | |
//Set our posts object in our global var | |
itemsArray = feed.items; | |
//Fetch the first image | |
getAndGo(accessToken); | |
return true; | |
})(); | |
} | |
//Function that pulls the image file for the next Instagram post | |
//And calls to upload it to my server | |
const getAndGo = function(accessToken) { | |
const item = itemsArray.shift(); | |
const imageUrl = item.enclosure.url; | |
const instagramLink = item.link; | |
const publishDate = item.pubDate; //Format Tue, 30 Oct 2018 15:59:02 +0900 | |
const description = item.contentSnippet; | |
//Upload the image | |
uploadImage(accessToken, imageUrl, publishDate, description, instagramLink); | |
} | |
//Function which handles uploading an image to the server | |
const uploadImage = function(accessToken, imageUrl, publishDate, description) { | |
console.log("Upload image called"); | |
const filename = imageUrl.substr(imageUrl.lastIndexOf('/') + 1); | |
const fullFilename = "/home/scripts/images/" + filename; | |
//Check if that file already exists | |
if (fs.existsSync(fullFilename)) { | |
console.log("File (" + fullFilename + ") already exists"); | |
console.log("This post has likely already been posted"); | |
//Get the next image | |
getAndGo(accessToken); | |
return false; | |
//File doesnt already exist | |
} else { | |
//Get the image and write it to the file system | |
request(imageUrl) | |
.pipe(fs.createWriteStream(fullFilename)) | |
.on('error', function (err) { | |
console.log("Error saving image"); | |
console.log(err); | |
}) | |
.on('close', function(){ | |
console.log('Done saving image'); | |
const type = mime.lookup(fullFilename); | |
var uploadOptions = { | |
url: 'https://thomasclowes.com/ghost/api/v0.1/uploads', | |
headers: { | |
'Authorization': 'Bearer ' + accessToken, | |
'Content-Type': 'image/jpeg' | |
}, | |
formData: { | |
uploadimage: fs.createReadStream(fullFilename), | |
} | |
}; | |
//Upload the image through the Ghost API | |
//This essentially makes a copy of the image | |
const postResponse = request.post(uploadOptions, function (error, r, imageUrl) { | |
if (error) { | |
console.log("Error uploading image"); | |
console.log(error); | |
} | |
//URL returned from Ghost API is enclosed in ". Remove these. | |
const processedImageUrl = imageUrl.replace(/"/g,''); | |
console.log(processedImageUrl); | |
console.log("Uploaded Image"); | |
//Create a Ghost post using the details we have | |
submitPost(accessToken, processedImageUrl, publishDate, description); | |
return true; | |
}); | |
}); | |
} | |
} | |
//Function that creates a Ghost post through the Ghost public API | |
const submitPost = function(accessToken, imageUrl, publishDate, description) { | |
const mobileDoc = { | |
version: "0.3.1", | |
atoms: [], | |
cards: [ | |
["image", {"caption": description, "src": imageUrl}], | |
["markdown",{"markdown":" This post was originally posted on [my Instagram](https://instagram.com/thomasclowes)."}] | |
], | |
markups: [], | |
sections: [[10,0],[10,1],[1,"p",[]]] | |
} | |
//We will make post titles the first sentence of description | |
const postTitle = description.substr(0, description.indexOf('.') !== -1 ? description.indexOf('.') : description.length); | |
const postSlug = slugify("Instagram " + postTitle); | |
const postTags = []; | |
//We will tag all posts with 'Instagram' | |
postTags.push({"name": "instagram"}); | |
//Filter out any hash tags and set them as tags on the post | |
const hashTags = description.split(' ').filter(v => v.startsWith('#')); | |
hashTags.forEach(function(hashTag) { | |
postTags.push({"name": hashTag.replace("#", "")}); | |
}); | |
//Post data object in a format accepted by the Ghost API | |
const postData = { | |
"posts": [{ | |
author: "1", | |
//featured: false, | |
feature_image: imageUrl, | |
language: "en_GB", | |
mobiledoc: JSON.stringify(mobileDoc), | |
meta_description: description, | |
custom_excerpt: description, | |
meta_title: postTitle, | |
//page: false, | |
published_by: null, | |
slug: postSlug, | |
status: "published", | |
tags: postTags, | |
title: postTitle, | |
published_at: publishDate | |
}] | |
}; | |
var options = { | |
url: 'https://thomasclowes.com/ghost/api/v0.1/posts', | |
headers: { | |
'Authorization': 'Bearer ' + accessToken, | |
'Content-Type': 'application/json' | |
} | |
}; | |
//Submit the post to the API | |
const postResponse = request.post(options, function (e, r, body) { | |
console.log(body); | |
console.log("Posted"); | |
//If there are still posts to process | |
//Lets process the next one | |
if (itemsArray.length != 0) { | |
console.log("Getting the next item. " +itemsArray.length + " left."); | |
getAndGo(accessToken); | |
} | |
return true; | |
}).form(postData); | |
} | |
//Get the Access Token/Begin | |
getAccessToken(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment