Skip to content

Commit

Permalink
Added colors, added support for highres images, added some initial tests
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 Aug 1, 2016
1 parent 6cbce82 commit cae06cd
Show file tree
Hide file tree
Showing 10 changed files with 120 additions and 24 deletions.
4 changes: 3 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
module.exports = {
"extends": ["motley"],
"parser": "babel-eslint",
"plugins": ["ava"],
"extends": ["motley", "plugin:ava/recommended"],
"rules": {
"no-console": 0,
"global-require": 0,
Expand Down
2 changes: 2 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
test.js
fixtures/**
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ npm install ascii-shot -g
```
Usage
$ ascii-shot <username>
Options
--highres, -h Show highres images
Examples
$ ascii-shot petetnt
Expand Down
12 changes: 10 additions & 2 deletions VERSIONS.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
# 1.0.0
# Versions

## 1.1.0

- Added colorized output #2
- Added support for showing highres images #4
- Added some initial tests

## 1.0.0

- Complete rewrite using the semi-public API `username/media`. Fixes #1.

# 0.0.1 - 0.0.3
## 0.0.1 - 0.0.3

- Legacy version using authenticated API communication.
Binary file modified assets/example.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 14 additions & 2 deletions bin/ascii-shot
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,28 @@ const meow = require("meow");
const cli = meow(`
Usage
$ ascii-shot <username>
Options
--highres, -h Show highres images
--noColor, -c No colors
Examples
$ ascii-shot petetnt
`);
$ ascii-shot petetnt --highres
$ ascii-shot petetnt --noColor
`, {
alias: {
"h": "highres",
"c": "noColor"
}
});

const username = cli.input[0];
const flags = cli.flags;

if (!username) {
console.error(" Error: You must pass an username");
cli.showHelp();
} else {
require("../lib/ascii-shot")(username);
require("../lib/ascii-shot")(username, flags);
}
2 changes: 2 additions & 0 deletions fixtures/fixture.json

Large diffs are not rendered by default.

77 changes: 60 additions & 17 deletions lib/ascii-shot.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ const cursor = ansi(process.stdout);
* Takes a HTML-formatted text and parses the containing ASCII image to text.
* Also writes the attached metadata to console.
* @param {String} text - HTML body
* @param {object} image - Object containing related metadata.
* @param {Object} image - Object containing related metadata.
* @param {Object} counter - Counter that contains the amount of images and current image number
* @param {Object} flags - flags passed to the cli
* @returns {Promise.resolve} - Resolved promise for chaining.
*/
function writeInstagramShot(text, image) {
function writeInstagramShot(text, image, counter, flags) {
const $ = cheerio.load(text);
const imageParts = $("font").children();

Expand All @@ -21,16 +23,36 @@ function writeInstagramShot(text, image) {
caption,
} = image;

cursor.write(`${"-".repeat(52)}${EOL}`);
const {
amount,
count,
} = counter;

const {
noColor,
highRes,
} = flags;

const repeatAmount = highRes ? 104 : 52;

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(52)}${EOL}`);
cursor.write(`${"-".repeat(repeatAmount)}${EOL}`);

imageParts.each((index, elem) => {
if (elem.name === "span") {
const $elem = $(elem);
cursor.red().write($elem.text()).reset();
const elemText = $elem.text();

if (noColor) {
cursor.write(elemText).reset();
} else {
const [, color] = $elem.attr("style").split(":");
cursor.hex(color).write(elemText).reset();
}
}

if (elem.name === "br") {
Expand All @@ -44,9 +66,10 @@ function writeInstagramShot(text, image) {
/**
* Formats the itemsArray to caption/likes/imageurl format
* @param {Array} itemsArray - Array of instagram items
* @param {Object} flags - flags passed to the cli
* @returns {Array} - Array of image urls
*/
const formatItemsArray = (itemsArray) => (
const formatItemsArray = (itemsArray, flags) => (
itemsArray.map((item) => {
const {
images,
Expand All @@ -62,7 +85,7 @@ const formatItemsArray = (itemsArray) => (

let url = null;

if (lowResolution) {
if (lowResolution && !flags.highRes) {
url = lowResolution.url.split("?")[0];
} else if (standardResolution) {
url = standardResolution.url.split("?")[0];
Expand All @@ -80,13 +103,15 @@ const formatItemsArray = (itemsArray) => (
/**
* Writes an image to the console
* @param {String} imageUrl - Url of the image to fetch
* @returns {Promise} - Res
* @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) => {
const writeImageToConsole = (image, counter, flags) => {
console.log(`Fetching ${image.url}...`);
return fetch(`${image.url}.html`)
.then((res) => res.text())
.then((text) => writeInstagramShot(text, image))
.then((text) => writeInstagramShot(text, image, counter, flags))
.catch((err) => {
console.error(" Error: Ressor fetching/parsing images:");
console.error(err.message);
Expand All @@ -96,8 +121,9 @@ const writeImageToConsole = (image) => {
/**
* 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) => {
const AsciiShot = (username, flags) => (
fetch(`https://instagram.com/${username}/media`)
.then((res) => res.json())
.then(json => {
Expand All @@ -109,10 +135,25 @@ const AsciiShot = (username) => {

let isFetching = false;

const instagramShots = formatItemsArray(itemsArray);
const instagramShots = formatItemsArray(itemsArray, flags);
const amount = instagramShots.length;
const hasRawMode = process.stdin.setRawMode; // for tests
let count = 0;

/**
* Fetches the next image or ends the program
* @param {Buffer} data - Data from process.stdin
*/
const fetchNextOrDie = (data) => {
process.stdin.setRawMode(false);
if (hasRawMode) {
process.stdin.setRawMode(false);
}
count = count + 1;

const counter = {
amount,
count,
};

if (isFetching) {
return;
Expand All @@ -124,10 +165,12 @@ const AsciiShot = (username) => {

isFetching = true;

writeImageToConsole(instagramShots.pop()).then(() => {
writeImageToConsole(instagramShots.pop(), counter, flags).then(() => {
isFetching = false;
if (instagramShots.length) {
process.stdin.setRawMode(true);
if (hasRawMode) {
process.stdin.setRawMode(true);
}
process.stdin.resume();
console.log("");
console.log("");
Expand All @@ -145,7 +188,7 @@ const AsciiShot = (username) => {
.catch((err) => {
console.error(` Error: Couldn't fetch images for username ${username}`);
console.error(err.message);
});
};
})
);

module.exports = AsciiShot;
10 changes: 8 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ascii-shot",
"version": "1.0.0",
"version": "1.1.0",
"description": ":rainbow: Get an users instagram feed as an ASCII version to stdout.",
"main": "ascii-shot.js",
"scripts": {
Expand Down Expand Up @@ -33,6 +33,12 @@
"ascii-shot": "bin/ascii-shot"
},
"devDependencies": {
"eslint-config-motley": "^1.0.2"
"ava": "^0.15.2",
"babel-eslint": "^6.1.2",
"eslint": "^3.2.1",
"eslint-config-motley": "^1.0.2",
"eslint-plugin-ava": "^2.5.0",
"execa": "^0.4.0",
"fetch-mock": "^5.0.3"
}
}
18 changes: 18 additions & 0 deletions test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import test from "ava";
import execa from "execa";
import fetchMock from "fetch-mock";
import asciiShot from "./lib/ascii-shot";

const fixtures = require("./fixtures/fixture.json");
fetchMock.mock("https://instagram.com/petetnt/media", fixtures);

test("should throw if no username is passed", async t => {
const { stderr } = await execa("./bin/ascii-shot", []);
t.is(stderr, " Error: You must pass an username");
});

test.serial("should call the semi-public api when passed an username", async t => {
asciiShot("petetnt", { highRes: false, noColors: false }).then(() => {
t.truthy(fetchMock.called("https://instagram.com/petetnt/media"));
});
});

0 comments on commit cae06cd

Please sign in to comment.