fca-priyansh
Version:
Facebook-chat-api made by Priyanshu Rajput
526 lines (462 loc) • 15.5 kB
JavaScript
;
var utils = require("../utils");
var log = require("npmlog");
/**
* Sticker API Module
* Provides access to Facebook's GraphQL-based sticker endpoints
* Made by @ChoruOfficial - Ported to fca-updated format
*/
/**
* Format the sticker pack list (store or tray)
* @param {object} data - Raw GraphQL response
* @returns {{ packs: Array<{id: string, name: string, thumbnail: string}>, page_info: object, store_id?: string }}
*/
function formatPackList(data) {
var trayPacks = data?.data?.picker_plugins?.sticker_picker?.sticker_store?.tray_packs?.edges;
var storePacks = data?.data?.viewer?.sticker_store?.available_packs?.edges;
var packData = storePacks || trayPacks;
if (!packData || !packData.edges) {
return { packs: [], page_info: { has_next_page: false } };
}
var formattedPacks = packData.edges.map(function(edge) {
if (!edge.node) return null;
return {
id: edge.node.id,
name: edge.node.name,
thumbnail: edge.node.thumbnail_image?.uri
};
}).filter(Boolean);
return {
packs: formattedPacks,
page_info: packData.page_info,
store_id: data?.data?.viewer?.sticker_store?.id
};
}
/**
* Format search result stickers
* @param {object} data - Raw GraphQL response
* @returns {Array<Object>}
*/
function formatStickerSearchResults(data) {
var stickers = data?.data?.sticker_search?.sticker_results?.edges;
if (!stickers) return [];
return stickers.map(function(edge) {
if (!edge.node) return null;
return {
type: "sticker",
ID: edge.node.id,
url: edge.node.image?.uri,
animatedUrl: edge.node.animated_image?.uri,
packID: edge.node.pack?.id,
label: edge.node.label || edge.node.accessibility_label,
stickerID: edge.node.id
};
}).filter(Boolean);
}
/**
* Format sticker pack content
* @param {object} data - Raw GraphQL response
* @returns {Array<Object>}
*/
function formatStickerPackResults(data) {
var stickers = data?.data?.sticker_pack?.stickers?.edges;
if (!stickers) return [];
return stickers.map(function(edge) {
if (!edge.node) return null;
return {
type: "sticker",
ID: edge.node.id,
url: edge.node.image?.uri,
animatedUrl: edge.node.animated_image?.uri,
packID: edge.node.pack?.id,
label: edge.node.label || edge.node.accessibility_label,
stickerID: edge.node.id
};
}).filter(Boolean);
}
/**
* Format AI-generated stickers
* @param {object} data - Raw GraphQL response
* @returns {Array<Object>}
*/
function formatAiStickers(data) {
var stickers = data?.data?.xfb_trending_generated_ai_stickers?.nodes;
if (!stickers) return [];
return stickers.map(function(node) {
return {
type: "sticker",
ID: node.id,
url: node.url,
label: node.label,
stickerID: node.id
};
}).filter(Boolean);
}
module.exports = function(defaultFuncs, api, ctx) {
/**
* Make a GraphQL request and handle login and error checking
* @param {object} form - Form data for the request
* @returns {Promise<object>}
*/
function makeRequest(form) {
return defaultFuncs
.post("https://www.facebook.com/api/graphql/", ctx.jar, form)
.then(utils.parseAndCheckLogin(ctx, defaultFuncs))
.then(function(resData) {
if (!resData) {
throw new Error("GraphQL request returned no data.");
}
if (resData.errors) {
log.error("StickerAPI GraphQL Error", resData.errors[0].message);
throw resData.errors[0];
}
return resData;
});
}
return {
/**
* Search for stickers by keyword
* @param {string} query - Search term
* @param {function} callback - Optional callback(err, result)
* @returns {Promise<Array<Object>>}
*/
search: function(query, callback) {
var resolveFunc = function() {};
var rejectFunc = function() {};
var returnPromise = new Promise(function(resolve, reject) {
resolveFunc = resolve;
rejectFunc = reject;
});
if (!callback) {
callback = function(err, data) {
if (err) return rejectFunc(err);
resolveFunc(data);
};
}
if (!query) {
return callback({ error: "Search query is required." });
}
var form = {
fb_api_caller_class: 'RelayModern',
fb_api_req_friendly_name: 'CometStickerPickerSearchResultsRootQuery',
variables: JSON.stringify({
scale: 3,
search_query: query,
sticker_height: 128,
sticker_width: 128,
stickerInterface: "MESSAGES"
}),
doc_id: '24004987559125954'
};
makeRequest(form)
.then(function(res) {
var results = formatStickerSearchResults(res);
log.info("stickers.search", "Found " + results.length + " stickers for query: " + query);
callback(null, results);
})
.catch(function(err) {
log.error("stickers.search", err);
callback(err);
});
return returnPromise;
},
/**
* List user's sticker packs
* @param {function} callback - Optional callback(err, result)
* @returns {Promise<Array<Object>>}
*/
listPacks: function(callback) {
var resolveFunc = function() {};
var rejectFunc = function() {};
var returnPromise = new Promise(function(resolve, reject) {
resolveFunc = resolve;
rejectFunc = reject;
});
if (!callback) {
callback = function(err, data) {
if (err) return rejectFunc(err);
resolveFunc(data);
};
}
var form = {
fb_api_caller_class: 'RelayModern',
fb_api_req_friendly_name: 'CometStickerPickerCardQuery',
variables: JSON.stringify({ scale: 3, stickerInterface: "MESSAGES" }),
doc_id: '10095807770482952'
};
makeRequest(form)
.then(function(res) {
var packs = formatPackList(res).packs;
log.info("stickers.listPacks", "Found " + packs.length + " user sticker packs");
callback(null, packs);
})
.catch(function(err) {
log.error("stickers.listPacks", err);
callback(err);
});
return returnPromise;
},
/**
* Get all available sticker packs from the store (with pagination)
* @param {function} callback - Optional callback(err, result)
* @returns {Promise<Array<Object>>}
*/
getStorePacks: function(callback) {
var resolveFunc = function() {};
var rejectFunc = function() {};
var returnPromise = new Promise(function(resolve, reject) {
resolveFunc = resolve;
rejectFunc = reject;
});
if (!callback) {
callback = function(err, data) {
if (err) return rejectFunc(err);
resolveFunc(data);
};
}
log.info("stickers.getStorePacks", "Starting to fetch all sticker packs from store...");
var allPacks = [];
var initialForm = {
fb_api_caller_class: 'RelayModern',
fb_api_req_friendly_name: 'CometStickersStoreDialogQuery',
variables: JSON.stringify({}),
doc_id: '29237828849196584'
};
makeRequest(initialForm)
.then(function(res) {
var result = formatPackList(res);
var packs = result.packs;
var page_info = result.page_info;
var store_id = result.store_id;
allPacks = allPacks.concat(packs);
log.info("stickers.getStorePacks", "Fetched first page with " + packs.length + " packs.");
// Handle pagination
function fetchNextPage() {
if (!page_info || !page_info.has_next_page) {
log.info("stickers.getStorePacks", "Finished fetching. Total unique packs found: " + allPacks.length);
return callback(null, allPacks);
}
log.info("stickers.getStorePacks", "Fetching next page with cursor: " + page_info.end_cursor);
var paginatedForm = {
fb_api_caller_class: 'RelayModern',
fb_api_req_friendly_name: 'CometStickersStorePackListPaginationQuery',
variables: JSON.stringify({
count: 20,
cursor: page_info.end_cursor,
id: store_id
}),
doc_id: '9898634630218439'
};
makeRequest(paginatedForm)
.then(function(nextRes) {
var paginatedResult = formatPackList(nextRes);
allPacks = allPacks.concat(paginatedResult.packs);
page_info = paginatedResult.page_info;
log.info("stickers.getStorePacks", "Fetched " + paginatedResult.packs.length + " more packs. Total now: " + allPacks.length);
fetchNextPage();
})
.catch(function(err) {
log.error("stickers.getStorePacks", err);
callback(err);
});
}
fetchNextPage();
})
.catch(function(err) {
log.error("stickers.getStorePacks", err);
callback(err);
});
return returnPromise;
},
/**
* Merge user's and store sticker packs into one list
* @param {function} callback - Optional callback(err, result)
* @returns {Promise<Array<Object>>}
*/
listAllPacks: function(callback) {
var resolveFunc = function() {};
var rejectFunc = function() {};
var returnPromise = new Promise(function(resolve, reject) {
resolveFunc = resolve;
rejectFunc = reject;
});
if (!callback) {
callback = function(err, data) {
if (err) return rejectFunc(err);
resolveFunc(data);
};
}
var self = this;
Promise.all([
new Promise(function(resolve, reject) {
self.listPacks(function(err, data) {
if (err) return reject(err);
resolve(data);
});
}),
new Promise(function(resolve, reject) {
self.getStorePacks(function(err, data) {
if (err) return reject(err);
resolve(data);
});
})
])
.then(function(results) {
var myPacks = results[0];
var storePacks = results[1];
var allPacksMap = {};
myPacks.forEach(function(pack) {
allPacksMap[pack.id] = pack;
});
storePacks.forEach(function(pack) {
allPacksMap[pack.id] = pack;
});
var allPacks = Object.keys(allPacksMap).map(function(key) {
return allPacksMap[key];
});
log.info("stickers.listAllPacks", "Total unique packs: " + allPacks.length);
callback(null, allPacks);
})
.catch(function(err) {
log.error("stickers.listAllPacks", err);
callback(err);
});
return returnPromise;
},
/**
* Add a sticker pack by ID
* @param {string} packID - The ID of the sticker pack
* @param {function} callback - Optional callback(err, result)
* @returns {Promise<Object>}
*/
addPack: function(packID, callback) {
var resolveFunc = function() {};
var rejectFunc = function() {};
var returnPromise = new Promise(function(resolve, reject) {
resolveFunc = resolve;
rejectFunc = reject;
});
if (!callback) {
callback = function(err, data) {
if (err) return rejectFunc(err);
resolveFunc(data);
};
}
if (!packID) {
return callback({ error: "Pack ID is required." });
}
var form = {
fb_api_caller_class: 'RelayModern',
fb_api_req_friendly_name: 'CometStickersStorePackMutationAddMutation',
variables: JSON.stringify({
input: {
pack_id: packID,
actor_id: ctx.userID,
client_mutation_id: Math.round(Math.random() * 10).toString()
}
}),
doc_id: '9877489362345320'
};
makeRequest(form)
.then(function(res) {
var pack = res.data.sticker_pack_add.sticker_pack;
log.info("stickers.addPack", "Successfully added sticker pack: " + packID);
callback(null, pack);
})
.catch(function(err) {
log.error("stickers.addPack", err);
callback(err);
});
return returnPromise;
},
/**
* Get all stickers in a pack
* @param {string} packID - Sticker pack ID
* @param {function} callback - Optional callback(err, result)
* @returns {Promise<Array<Object>>}
*/
getStickersInPack: function(packID, callback) {
var resolveFunc = function() {};
var rejectFunc = function() {};
var returnPromise = new Promise(function(resolve, reject) {
resolveFunc = resolve;
rejectFunc = reject;
});
if (!callback) {
callback = function(err, data) {
if (err) return rejectFunc(err);
resolveFunc(data);
};
}
if (!packID) {
return callback({ error: "Pack ID is required." });
}
var form = {
fb_api_caller_class: 'RelayModern',
fb_api_req_friendly_name: 'CometStickerPickerPackContentRootQuery',
variables: JSON.stringify({
packID: packID,
stickerWidth: 128,
stickerHeight: 128,
scale: 3
}),
doc_id: '23982341384707469'
};
makeRequest(form)
.then(function(res) {
var stickers = formatStickerPackResults(res);
log.info("stickers.getStickersInPack", "Found " + stickers.length + " stickers in pack: " + packID);
callback(null, stickers);
})
.catch(function(err) {
log.error("stickers.getStickersInPack", err);
callback(err);
});
return returnPromise;
},
/**
* Get trending AI-generated stickers
* @param {Object} options - Options object { limit: number }
* @param {function} callback - Optional callback(err, result)
* @returns {Promise<Array<Object>>}
*/
getAiStickers: function(options, callback) {
var resolveFunc = function() {};
var rejectFunc = function() {};
var returnPromise = new Promise(function(resolve, reject) {
resolveFunc = resolve;
rejectFunc = reject;
});
// Handle optional parameters
if (typeof options === 'function') {
callback = options;
options = {};
}
options = options || {};
var limit = options.limit || 10;
if (!callback) {
callback = function(err, data) {
if (err) return rejectFunc(err);
resolveFunc(data);
};
}
var form = {
fb_api_caller_class: 'RelayModern',
fb_api_req_friendly_name: 'CometStickerPickerStickerGeneratedCardQuery',
variables: JSON.stringify({ limit: limit }),
doc_id: '24151467751156443'
};
makeRequest(form)
.then(function(res) {
var stickers = formatAiStickers(res);
log.info("stickers.getAiStickers", "Found " + stickers.length + " AI stickers");
callback(null, stickers);
})
.catch(function(err) {
log.error("stickers.getAiStickers", err);
callback(err);
});
return returnPromise;
}
};
};