Skip to content

Commit

Permalink
Now supports pagination, added caption formatting
Browse files Browse the repository at this point in the history
Signed-off-by: petetnt <pete.a.nykanen@gmail.com>
  • Loading branch information
petetnt committed Feb 19, 2017
1 parent f456a76 commit 5f11047
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 62 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Ascii-shot
# asciiShot `ascii-shot`

:rainbow: Get an users Instagram feed as an ASCII version to `stdout`.

Expand Down
5 changes: 5 additions & 0 deletions VERSIONS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Versions

## 1.2.0

- Now supports pagination!
- Caption formatting

## 1.1.0

- Added colorized output #2
Expand Down
2 changes: 1 addition & 1 deletion bin/ascii-shot
Original file line number Diff line number Diff line change
Expand Up @@ -26,5 +26,5 @@ if (!username) {
console.error(" Error: You must pass an username");
cli.showHelp();
} else {
require("../lib/ascii-shot")(username, flags);
require("../lib/ascii-shot")(username, null, flags);
}
154 changes: 95 additions & 59 deletions lib/ascii-shot.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ const cursor = ansi(process.stdout);
* Also writes the attached metadata to console.
* @param {String} text - HTML body
* @param {Object} image - Object containing related metadata.
* @param {Object} counter - Counter that contains the amount of images and current image number
* @param {Object} counter - Counter that contains the current image number
* @param {Object} flags - flags passed to the cli
* @returns {Promise.resolve} - Resolved promise for chaining.
*/
function writeInstagramShot(text, image, counter, flags) {
function writeInstagramShot(text, image, count, flags) {
const $ = cheerio.load(text);
const imageParts = $("font").children();

Expand All @@ -23,24 +23,35 @@ function writeInstagramShot(text, image, counter, flags) {
caption,
} = image;

const {
amount,
count,
} = counter;

const {
noColor,
highRes,
} = flags;

const repeatAmount = highRes ? 104 : 52;
const lineLength = highRes ? 104 : 52;

cursor.write(`${"-".repeat(lineLength)}${EOL}`);
cursor.write(`${count}${EOL}`);

const captionWords = caption.split(" ");
let line = "";

for (const word of captionWords) {
line = `${line} ${word}`;

if (line.length > lineLength) {
line = "";
cursor.write(EOL);
}

cursor.write(`${word} `);
}

cursor.write(EOL);

cursor.write(`${"-".repeat(repeatAmount)}${EOL}`);
cursor.write(`${count}/${amount}${EOL}`);
cursor.write(`Caption: ${caption}${EOL}`);
cursor.write(`Created at: ${date}${EOL}`);
cursor.write(`Likes: ${likes}${EOL}`);
cursor.write(`${"-".repeat(repeatAmount)}${EOL}`);
cursor.write(`${"-".repeat(lineLength)}${EOL}`);

imageParts.each((index, elem) => {
if (elem.name === "span") {
Expand Down Expand Up @@ -72,6 +83,7 @@ function writeInstagramShot(text, image, counter, flags) {
const formatItemsArray = (itemsArray, flags) => (
itemsArray.map((item) => {
const {
id,
images,
likes,
caption,
Expand All @@ -92,6 +104,7 @@ const formatItemsArray = (itemsArray, flags) => (
}

return {
id,
likes: likes.count,
caption: caption ? caption.text : "",
date: new Date(createdTime * 1000),
Expand All @@ -103,42 +116,58 @@ const formatItemsArray = (itemsArray, flags) => (
/**
* Writes an image to the console
* @param {String} imageUrl - Url of the image to fetch
* @param {Object} counter - Counter that contains the amount of images and current image number
* @param {Object} counter - Counter that contains the amount of images and current image number
* @param {Object} flags - flags passed to the cli
* @returns {Promise} - Resolves when image is written
*/
const writeImageToConsole = (image, counter, flags) => {
console.log(`Fetching ${image.url}...`);
return fetch(`${image.url}.html`)
.then((res) => res.text())
.then((text) => writeInstagramShot(text, image, counter, flags))
.catch((err) => {
console.error(" Error: Ressor fetching/parsing images:");
console.error(err.message);
});
};
const writeImageToConsole = (image, counter, flags) => fetch(`${image.url}.html`)
.then((res) => res.text())
.then((text) => writeInstagramShot(text, image, counter, flags))
.catch((err) => {
console.error(" Error: Errors fetching/parsing images:");
console.error(err.message);
});

/**
* Fetches the latest Instagram shot of the owner of the access_token
* @param {String} token - access token
* @param {Object} flags - flags passed to the cli
*/
const AsciiShot = (username, flags) => (
fetch(`https://instagram.com/${username}/media`)
.then((res) => res.json())
.then(json => {
const itemsArray = json.items;
let IS_FETCHING = false;

const fetchPageForUsername = (username, maxId, flags) => {
const baseUrl = `https://instagram.com/${username}/media`;
const url = `${baseUrl}/${maxId ? `?max_id=${maxId}` : ""}`;

IS_FETCHING = true;

return fetch(url).then((res) => res.json()).then(json => {
const {
items: itemsArray,
more_available: moreAvailable,
} = json;

if (!json || !itemsArray) {
throw new Error("No items found.");
}

let isFetching = false;
IS_FETCHING = false;

const instagramShots = formatItemsArray(itemsArray, flags);
const amount = instagramShots.length;

return {
instagramShots,
moreAvailable,
};
});
};

/**
* Fetches the latest Instagram shot of username
* @param {String} username - username
* @param {String} maxId - lastId fetched
* @param {Object} flags - flags passed to the cli
*/
const asciiShot = (username, maxId, flags, count = 0) => (
fetchPageForUsername(username, maxId, flags)
.then(({ instagramShots, moreAvailable }) => {
const hasRawMode = process.stdin.setRawMode; // for tests
let count = 0;
let lastId = null;

/**
* Fetches the next image or ends the program
Expand All @@ -148,38 +177,45 @@ const AsciiShot = (username, flags) => (
if (hasRawMode) {
process.stdin.setRawMode(false);
}
count = count + 1;

const counter = {
amount,
count,
};

if (isFetching) {
if (IS_FETCHING) {
return;
}


if (data && data.toString("hex") !== "20") {
process.exit(0);
}

isFetching = true;
const image = instagramShots.pop();

writeImageToConsole(instagramShots.pop(), counter, flags).then(() => {
isFetching = false;
if (instagramShots.length) {
if (hasRawMode) {
process.stdin.setRawMode(true);
if (!image && moreAvailable) {
process.stdin.removeAllListeners("data");
console.log("Fetching more images...");
asciiShot(username, lastId, flags, count);
} else {
count = count + 1; // eslint-disable-line

lastId = image.id;
IS_FETCHING = true;

writeImageToConsole(image, count, flags).then(() => {
if (instagramShots.length || moreAvailable) {
IS_FETCHING = false;

if (hasRawMode) {
process.stdin.setRawMode(true);
}
process.stdin.resume();
console.log("");
console.log("");
console.log("Press space to fetch the next one or any other key to exit");
} else {
console.log(`No more images for ${username} :)`);
process.exit(0);
}
process.stdin.resume();
console.log("");
console.log("");
console.log("Press space to fetch the next one or any other key to exit");
} else {
console.log(`No more images for ${username} :)`);
process.exit(0);
}
});
});
}
};

fetchNextOrDie();
Expand All @@ -191,4 +227,4 @@ const AsciiShot = (username, flags) => (
})
);

module.exports = AsciiShot;
module.exports = asciiShot;
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ascii-shot",
"version": "1.1.0",
"version": "1.2.0",
"description": ":rainbow: Get an users instagram feed as an ASCII version to stdout.",
"main": "ascii-shot.js",
"scripts": {
Expand Down

0 comments on commit 5f11047

Please sign in to comment.