diff --git a/.gitignore b/.gitignore index 2b22a9a..13c8d29 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,4 @@ node_modules/ config/*.js !config/example.js -/* output/ diff --git a/app.js b/app.js index 601db8a..03b26df 100644 --- a/app.js +++ b/app.js @@ -10,8 +10,9 @@ const dissectLink = require('./dissectLink.js'); const fetchContent = require('./fetchContent.js'); const reddit = new snoowrap(config.api); +const user = yargs.user; -reddit.getUser(yargs.user).getSubmissions({ +reddit.getUser(user).getSubmissions({ sort: 'top' }).then(submissions => { const curatedPosts = submissions.map(submission => { @@ -20,6 +21,8 @@ reddit.getUser(yargs.user).getSubmissions({ title: submission.title, permalink: submission.permalink, url: submission.url, + datetime: submission.created_utc, + subreddit: submission.subreddit.display_name, host: dissectLink(submission.url) }; }); @@ -37,6 +40,6 @@ reddit.getUser(yargs.user).getSubmissions({ return acc; }, [])); -}).then(fetchContent).catch(error => { +}).then(posts => fetchContent(posts, user)).catch(error => { note(error); }); diff --git a/dissectLink.js b/dissectLink.js new file mode 100644 index 0000000..0564b77 --- /dev/null +++ b/dissectLink.js @@ -0,0 +1,30 @@ +'use strict'; + +const urlPattern = require('url-pattern'); + +const hosts = [{ + method: 'imgurImage', + pattern: new urlPattern('http(s)\\://(i.)imgur.com/:id(.:ext)(?:num)') +}, { + method: 'imgurAlbum', + pattern: new urlPattern('http(s)\\://imgur.com/:type/:id') +}]; + +module.exports = function dissectLink(url) { + return hosts.reduce((acc, host) => { + if(acc) { + return acc; + } + + const match = host.pattern.match(url); + + if(match) { + return Object.assign(match, { + url: url, + method: host.method + }); + } + + return null; + }, null); +}; diff --git a/fetchContent.js b/fetchContent.js new file mode 100644 index 0000000..0f71220 --- /dev/null +++ b/fetchContent.js @@ -0,0 +1,47 @@ +'use strict'; + +const fs = require('fs-extra'); +const path = require('path'); +const fetch = require('node-fetch'); + +function saveToDisk(buffer, item, index, filename, post, user) { + const stream = fs.createWriteStream(filename); + + return new Promise((resolve, reject) => { + buffer.body.pipe(stream).on('error', error => { + reject(error); + }).on('finish', () => { + console.log(`Fetched and saved ${filename}`); + + resolve(filename); + }); + }); +}; + +function fetchItem(item, index, post, user) { + return fetch(item.url).then(res => { + return res.ok ? res : Promise.reject(`Failed to fetch ${item.url}`); + }); +}; + +module.exports = function(posts, user) { + return Promise.all(posts.map(post => { + const filepath = post.content.album ? `output/${user}/${post.content.album.datetime} - ${post.content.album.id} - ${post.title}/` : `output/${user}/`; + + return Promise.resolve().then(() => { + if(post.content.album) { + return fs.ensureDir(filepath); + }; + }).then(() => { + return Promise.all(post.content.items.map((item, index) => { + return fetchItem(item, index, post, user).then(buffer => Object.assign(item, {buffer})); + })); + }).then(items => { + return Promise.all(items.map((item, index) => { + const filename = post.content.album ? `${filepath}${index + 1} - ${item.id}.jpg` : `${filepath}${item.datetime} - ${item.id}.jpg`; + + return saveToDisk(item.buffer, item, index, filename, post, user) + })); + }); + })); +}; diff --git a/methods/imgurAlbum.js b/methods/imgurAlbum.js new file mode 100644 index 0000000..c7c37e6 --- /dev/null +++ b/methods/imgurAlbum.js @@ -0,0 +1,38 @@ + 'use strict'; + +const note = require('note-log'); +const util = require('util'); +const config = require('config'); +const fetch = require('node-fetch'); + +function imgurAlbum(post) { + return fetch(`https://api.imgur.com/3/album/${post.host.id}`, { + headers: { + 'Authorization': `Client-ID ${config.methods.imgur.clientId}` + } + }).then(res => res.json()).then(res => { + return { + album: { + id: res.data.id, + url: res.data.link, + title: res.data.title, + description: res.data.description, + datetime: res.data.datetime, + original: res.data + }, + items: res.data.images.map(item => ({ + id: item.id, + url: item.link, + title: item.title, + description: item.description, + datetime: item.datetime, + type: item.type, + original: item + })) + }; + }).catch(error => { + note(error); + }); +}; + +module.exports = imgurAlbum; diff --git a/methods/imgurImage.js b/methods/imgurImage.js new file mode 100644 index 0000000..3ebcd12 --- /dev/null +++ b/methods/imgurImage.js @@ -0,0 +1,31 @@ + 'use strict'; + +const note = require('note-log'); +const util = require('util'); +const config = require('config'); +const fetch = require('node-fetch'); + +function imgurImage(post) { + return fetch(`https://api.imgur.com/3/image/${post.host.id}`, { + headers: { + 'Authorization': `Client-ID ${config.methods.imgur.clientId}` + } + }).then(res => res.json()).then(res => { + return { + album: null, + items: [{ + id: res.data.id, + url: res.data.link, + title: res.data.title, + description: res.data.description, + type: res.data.type, + datetime: res.data.datetime, + original: res.data + }] + }; + }).catch(error => { + note(error); + }); +}; + +module.exports = imgurImage; diff --git a/methods/methods.js b/methods/methods.js new file mode 100644 index 0000000..3e9fd9b --- /dev/null +++ b/methods/methods.js @@ -0,0 +1,9 @@ +'use strict'; + +const imgurImage = require('./imgurImage.js'); +const imgurAlbum = require('./imgurAlbum.js'); + +module.exports = { + imgurImage: imgurImage, + imgurAlbum: imgurAlbum +};