diff --git a/DOCS.md b/DOCS.md
index 69177f53..7ee7085b 100644
--- a/DOCS.md
+++ b/DOCS.md
@@ -17,6 +17,7 @@
* [`api.getCurrentUserID`](#getCurrentUserID)
* [`api.getEmojiUrl`](#getEmojiUrl)
* [`api.getFriendsList`](#getFriendsList)
+* [`api.getNotifications`](#getNotifications)
* [`api.getThreadHistory`](#getThreadHistory)
* [`api.getThreadInfo`](#getThreadInfo)
* [`api.getThreadList`](#getThreadList)
@@ -544,6 +545,37 @@ login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, ap
---------------------------------------
+
+### api.getNotifications(amount, callback)
+
+Returns an array of objects with up to `amount` most recent notifications.
+
+__Arguments__
+
+* `callback(err, arr)` - A callback called when the query is done (either with an error or with an confirmation object). `arr` is an array of objects with the following fields: `id`, `text`, `html`, `time`, `seen`, `read`. `html` is the same as `text` but with ranges emphasized. `time`, `seen`, and `read` are all millisecond timestamps.
+
+__Example__
+
+```js
+const fs = require("fs");
+const login = require("facebook-chat-api");
+
+login({appState: JSON.parse(fs.readFileSync('appstate.json', 'utf8'))}, (err, api) => {
+ if(err) return console.error(err);
+
+ api.getNotifications((err, data) => {
+ if(err) return console.error(err);
+
+ data.forEach(notification => {
+ if(!notification.seen)
+ console.log(new Date(notification.time), notification.text);
+ });
+ });
+});
+```
+
+---------------------------------------
+
### api.getThreadHistory(threadID, amount, timestamp, callback)
diff --git a/README.md b/README.md
index efec9d3b..67d3ee25 100644
--- a/README.md
+++ b/README.md
@@ -66,6 +66,7 @@ Result:
* [`api.getAppState`](DOCS.md#getAppState)
* [`api.getCurrentUserID`](DOCS.md#getCurrentUserID)
* [`api.getFriendsList`](DOCS.md#getFriendsList)
+* [`api.getNotifications`](DOCS.md#getNotifications)
* [`api.getThreadHistory`](DOCS.md#getThreadHistory)
* [`api.getThreadInfo`](DOCS.md#getThreadInfo)
* [`api.getThreadList`](DOCS.md#getThreadList)
diff --git a/index.js b/index.js
index 95a6785f..b7cfe1b1 100644
--- a/index.js
+++ b/index.js
@@ -91,6 +91,7 @@ function buildAPI(globalOptions, html, jar) {
'getCurrentUserID',
'getEmojiUrl',
'getFriendsList',
+ 'getNotifications',
'getThreadHistory',
'getThreadInfo',
'getThreadList',
diff --git a/src/getNotifications.js b/src/getNotifications.js
new file mode 100644
index 00000000..081d97fc
--- /dev/null
+++ b/src/getNotifications.js
@@ -0,0 +1,61 @@
+"use strict";
+
+var utils = require("../utils");
+var log = require("npmlog");
+
+function formatText(notification, boldStart, boldEnd) {
+ const boldChars = boldStart.length + boldEnd.length
+ let formattedText = notification.title.text
+ notification.title.ranges.forEach( (range, i) => {
+ let start = range.offset + i * boldChars
+ let end = range.offset + range.length + i * boldChars
+ formattedText =
+ formattedText.slice( 0, start ) + boldStart +
+ formattedText.slice( start, end ) + boldEnd +
+ formattedText.slice( end )
+ })
+ return formattedText;
+}
+
+function formatData(obj) {
+ return obj.nodes.map( notification => {
+ return {
+ id: notification.alert_id,
+ text: notification.title.text,
+ html: formatText(notification, "", ""),
+ time: notification.timestamp.time * 1000,
+ seen: notification.first_seen_time * 1000,
+ read: notification.first_read_time * 1000
+ };
+ });
+}
+
+module.exports = function(defaultFuncs, api, ctx) {
+ return function getNotifications(amount, callback) {
+ if (!callback) {
+ throw { error: "getNotifications: need callback" };
+ }
+
+ defaultFuncs
+ .postFormData(
+ "https://www.facebook.com/ajax/notifications/client/get.php",
+ ctx.jar,
+ {},
+ { length: amount }
+ )
+ .then(utils.parseAndCheckLogin(ctx, defaultFuncs))
+ .then(function(resData) {
+ if (!resData) {
+ throw { error: "getNotifications returned empty object." };
+ }
+ if (resData.error) {
+ throw resData;
+ }
+ callback(null, formatData(resData.payload));
+ })
+ .catch(function(err) {
+ log.error("getNotifications", err);
+ return callback(err);
+ });
+ };
+};
diff --git a/test/test.js b/test/test.js
index 15760837..5beeb18b 100644
--- a/test/test.js
+++ b/test/test.js
@@ -366,6 +366,26 @@ describe('Login:', function() {
});
});
+ it('should get notifications', function (done) {
+ api.getNotifications(function(err, data) {
+ try {
+ checkErr(done)(err);
+ assert(getType(data) === "Array");
+ data.map(v => {
+ assert(getType(v.id) === "String");
+ assert(getType(v.text) === "String");
+ assert(getType(v.html) === "String");
+ assert(getType(v.time) === "Number");
+ assert(getType(v.seen) === "Number");
+ assert(getType(v.read) === "Number");
+ })
+ done();
+ } catch(e){
+ done(e);
+ }
+ });
+ });
+
it('should parse share attachment correctly', function () {
var formatted = formatDeltaMessage(shareAttachmentFixture);
assert(formatted.attachments[0].type === "share");