@flowdegree/swarmapp-api
Version:
A javascript wrapper for swarmapp (foursquare) API
556 lines (546 loc) • 19 kB
JavaScript
"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var src_exports = {};
__export(src_exports, {
default: () => SwarmappApi
});
module.exports = __toCommonJS(src_exports);
// src/utils/index.ts
var between = (min, max) => {
return Math.floor(Math.random() * (max - min) + min);
};
var createLatLngString = (lat, lng) => {
return `${lat},${lng}`;
};
function getLL() {
return this.config.ll;
}
function log(message) {
let _prefix = `${(/* @__PURE__ */ new Date()).toLocaleString()} - `;
_prefix += typeof this?.user?.firstName != "undefined" ? this?.user?.firstName : this?.user?.id;
console.log(`${_prefix}) `, message);
}
function error(error2) {
let _prefix = `${(/* @__PURE__ */ new Date()).toLocaleString()} - `;
_prefix += typeof this?.user?.firstName != "undefined" ? this?.user?.firstName : "unknown user";
_prefix += " - Error: ";
switch (error2?.meta?.code) {
case 401:
console.error(`${_prefix} [${error2.meta.errorType}] ${error2.meta.errorDetail}`);
throw new Error(error2);
default:
console.error(JSON.stringify(`${_prefix} ${error2}`, null, 4));
throw new Error(error2);
}
}
// src/api/main.ts
async function initialize() {
try {
const response = await this.getUser();
this.user = response?.data?.response?.user;
return true;
} catch (error2) {
this.error("Could not authenticate user");
return false;
}
}
// src/api/users.ts
var import_axios = __toESM(require("axios"));
var import_querystring = __toESM(require("querystring"));
async function getFriends(user_id = "self") {
this.config.user_id = user_id || this.user?.id;
try {
const result = await import_axios.default.get(this.basePath + "users/" + user_id + "/friends", { "params": this.config });
return result.data.response.friends;
} catch (error2) {
console.log(`error occured while getting friends`);
this.error(error2);
return null;
}
}
async function getFollowings(user_id = "self") {
this.config.user_id = user_id || this.user?.id;
this.config.m = "foursquare";
this.config.user_id = user_id;
try {
const result = await import_axios.default.get(this.basePath + "users/" + user_id + "/following", { "params": this.config });
return result.data.response.following;
} catch (error2) {
console.log(`error occured while getting followings`);
this.error(error2);
return null;
}
}
async function getFollowers(user_id = "self") {
this.user_id = user_id || this.user?.id;
this.config.m = "foursquare";
this.config.user_id = user_id;
try {
const result = await import_axios.default.get(this.basePath + "users/" + user_id + "/followers", { "params": this.config });
return result.data.response.followers;
} catch (error2) {
console.log(`error occured while getting followers`);
this.error(error2);
return null;
}
}
async function getUser(user_id = "self") {
try {
const result = await import_axios.default.get(`${this.basePath}users/${user_id}`, { "params": this.config });
return result;
} catch (error2) {
console.log(`error occured while getting user`);
this.error(error2);
throw new Error("Error getting user data, maybe an authentication error ?");
return;
}
}
async function getUserProfile(user_id = "self") {
try {
const result = await import_axios.default.get(`${this.basePath}users/${user_id}/profile`, { "params": this.config });
return result;
} catch (error2) {
console.log(`error occured while getting user`);
this.error(error2);
throw new Error("Error getting user data, maybe an authentication error ?");
}
}
async function getCheckins(user_id = "self", limit = 100, afterTimestamp) {
if (typeof afterTimestamp !== "undefined") {
this.config.afterTimeStamp = afterTimestamp;
}
this.config.user_id = user_id;
this.config.limit = limit;
try {
const result = await import_axios.default.get(`${this.basePath}users/${user_id}/checkins`, { "params": this.config });
return result;
} catch (error2) {
console.log(`error occured while getting checkins`);
this.error(error2);
return;
}
}
async function addFriendByID(user_id) {
try {
const userIdStr = user_id.toString();
const parameters = {
oauth_token: this.config.oauth_token,
v: this.config.v
};
const result = await this.getUserProfile(userIdStr);
const newFriend = result?.data?.response?.user;
if (newFriend?.relationship === "none") {
const postUrl = `${this.basePath}users/${userIdStr}/request`;
console.log(`Adding friend by id ${newFriend.handle}...`);
const result2 = await import_axios.default.post(`${postUrl}?${import_querystring.default.stringify(parameters)}`);
return result2.data.response.user;
} else {
return false;
}
} catch (error2) {
console.log(`error occured while adding friend by id ${user_id}`);
return false;
}
}
async function getLastSeen(user_id = "self", limit = 100) {
this.config.user_id = user_id;
this.config.limit = limit;
try {
return getUser(user_id);
} catch (error2) {
console.log(`error occured while getting last seen`);
this.error(error2);
}
}
async function getGeos(user_id = "self") {
this.config.user_id = user_id;
delete this.config.afterTimeStamp;
try {
const response = await import_axios.default.get(this.basePath + "/users/" + user_id + "/map", { "params": this.config });
return response.data.response;
} catch (error2) {
console.log(`error occured while getting geos`);
this.error(error2);
}
}
// src/api/checkins.ts
var import_axios2 = __toESM(require("axios"));
var import_querystring2 = __toESM(require("querystring"));
async function checkIn(venue_id, silent = false) {
if (silent) {
this.config.broadcast = "private";
}
this.config.venueId = venue_id;
const venue_info = await this.getVenue(venue_id);
this.config.ll = createLatLngString(venue_info.location.lat, venue_info.location.lng);
try {
const result = await import_axios2.default.post(this.basePath + "checkins/add", import_querystring2.default.stringify(this.config));
const checkin = result.data.response?.checkin;
return checkin;
} catch (error2) {
console.log(`error occured while checking in`);
this.error(error2);
return;
}
}
async function getRecent(limit = 100, ll) {
this.config.limit = limit;
this.config.afterTimeStamp = (Math.floor(Date.now() / 1e3) - 1 * 24 * 60 * 60).toString();
if (typeof ll !== "undefined") {
this.config.ll = ll;
}
try {
const result = await import_axios2.default.get(this.basePath + "checkins/recent", {
params: this.config,
paramsSerializer: (params) => {
return import_querystring2.default.stringify(params);
}
});
return result.data.response.recent;
} catch (error2) {
console.log(`error occured while getting recent`);
this.error(error2);
return;
}
}
async function likeCheckin(checkin_id) {
try {
const result = await import_axios2.default.post(this.basePath + "checkins/" + checkin_id + "/like", import_querystring2.default.stringify(this.config));
return result;
} catch (error2) {
this.error(error2.response.data);
return;
}
}
// src/api/venues.ts
var import_axios3 = __toESM(require("axios"));
var import_querystring3 = __toESM(require("querystring"));
async function getVenue(venue_id) {
try {
const result = await import_axios3.default.get(`${this.basePath}venues/${venue_id}/`, { "params": this.config });
return result.data.response.venue;
} catch (error2) {
console.log(`error occured while getting venue`);
throw new Error("Error getting venue data, maybe an authentication error ?");
return;
}
}
async function getTrending(limit = 50, ll, near, radius = 1e5) {
this.config.limit = limit;
this.config.radius = radius;
if (typeof ll !== "undefined") {
this.config.ll = ll;
} else {
this.config.near = near;
}
try {
const result = await import_axios3.default.get(this.basePath + "venues/trending", {
params: this.config,
paramsSerializer: (params) => {
return import_querystring3.default.stringify(params);
}
});
return result.data.response.venues;
} catch (error2) {
console.log(`error occured while getting trending venues`);
this.error(error2);
return;
}
}
// src/api/authentication.ts
var import_axios4 = __toESM(require("axios"));
var import_querystring4 = __toESM(require("querystring"));
async function login(username, password, client_id, client_secret) {
const params = {
client_id,
client_secret,
username,
password,
grant_type: "password"
};
try {
const response = await import_axios4.default.post(this.basePath + "/oauth2/access_token", null, { params });
this.config.access_token = response.data.access_token;
return response.data.access_token;
} catch (error2) {
console.log(`error occured while logging in`);
this.error(error2);
return;
}
}
async function initiatemultifactorlogin(username, password, client_id, client_secret) {
const params = {
...this.config,
client_id,
client_secret,
username,
password
};
console.log(password);
try {
const response = await import_axios4.default.post(this.basePath + "private/initiatemultifactorlogin", import_querystring4.default.stringify(params));
this.flowId = response.data.flowId;
return response.data;
} catch (error2) {
console.log(`error occured while initiating multifactor login`);
this.error(error2);
return error2;
}
}
async function completemultifactorlogin(code, client_id, client_secret) {
const params = {
...this.config,
client_id,
client_secret,
code,
flowId: this.flowId
};
try {
const response = await import_axios4.default.post(this.basePath + "private/completemultifactorlogin", import_querystring4.default.stringify(params));
this.config.oauth_token = response.data.oauth_token;
return response.data.access_token;
} catch (error2) {
console.log(`error occured while completing multifactor login`);
this.error(error2);
return;
}
}
// src/api/private.ts
var import_axios5 = __toESM(require("axios"));
var import_querystring5 = __toESM(require("querystring"));
async function private_log() {
const FormData = require("form-data");
const formData = new FormData();
formData.append("altAcc", this.config.altAcc);
formData.append("llAcc", this.config.llAcc);
formData.append("floorLevel", this.config.floorLevel);
formData.append("alt", this.config.alt);
formData.append("csid", "1243");
formData.append("v", this.config.v);
formData.append("oauth_token", this.config.oauth_token);
formData.append("m", this.config.m);
formData.append("ll", this.config.ll);
formData.append("background", "true");
const script = [{ "name": "ios-metrics", "csid": 1243, "ctc": 4, "metrics": [{ "rid": "642a1e4371f95f2eb16b8eda", "n": "SwarmTimelineFeedViewController", "im": "3-3", "vc": 1 }], "event": "background", "cts": 1680481860378182e-6 }];
const stringified = JSON.stringify(script);
formData.append("loglines", stringified, { filename: "loglines", contentType: "application/json" });
try {
const result = await import_axios5.default.post(this.basePath + "private/log", formData, {
headers: {
...formData.getHeaders()
}
});
return result;
} catch (error2) {
console.log(`error occured while private logging`);
this.error(error2);
return;
}
}
async function register_device() {
const params = {
limitAdsTracking: "1",
carrier: "stc",
hasWatch: "1",
csid: "1242",
alt: "11.791945",
llAcc: "14.825392",
otherDeviceIds: "6054750ee01fbc1e3492a745,61187d1fceb2110097a0fc02",
ll: "21.530136,39.172863",
altAcc: "17.547791",
locationAuthorizationStatus: "authorizedwheninuse",
token: "ec0718c5d042b63587c14d461bb077d1262811456c4799558e1df2616f02cc9a",
oauth_token: "DW233H4JWJZ0E14QU01LFWUZL4RDQPLAF10BAJEI2FTWNOKH",
iosSettings: "0",
m: "swarm",
floorLevel: "2146959360",
measurementSystem: "metric",
uniqueDevice: "6054750ee01fbc1e3492a745",
v: "20221101",
backgroundRefreshStatus: "available"
};
try {
const result = await import_axios5.default.post(this.basePath + "/private/registerdevice ", import_querystring5.default.stringify(params));
const registeration = result.data.response?.checkin;
return registeration;
} catch (error2) {
console.log(`error occured while registering device`);
this.error(error2);
return;
}
}
// src/index.ts
var SwarmappApi = class {
config;
basePath;
headers;
user;
flowId;
initialize;
getFriends;
getFollowings;
getFollowers;
getUser;
addFriendByID;
getLastSeen;
getGeos;
getUserProfile;
checkIn;
getRecent;
getCheckins;
likeCheckin;
completemultifactorlogin;
initiatemultifactorlogin;
getTrending;
getVenue;
log;
error;
getLL;
login;
register_device;
private_log;
constructor(oauth_token) {
this.config = {
m: "swarm",
v: "20221101",
// A random coordinate to use between calls imitating regular behavior
ll: createLatLngString("26.30" + between(34e10, 499999999999), "50.1" + between(287e10, 3119999999999)),
//latitude/longitude
altAcc: "30.000000",
llAcc: "14.825392",
floorLevel: "2146959360",
alt: "12.275661"
};
this.basePath = "https://api.foursquare.com/v2/";
this.headers = {
"User-Agent": "com.foursquare.robin.ios.phone:20230316.2230.52:20221101:iOS 16.1.1:iPhone13,4"
};
if (oauth_token) {
this.config.oauth_token = oauth_token;
}
this.initialize = initialize.bind(this);
this.getFriends = getFriends.bind(this);
this.getFollowings = getFollowings.bind(this);
this.getFollowers = getFollowers.bind(this);
this.getUser = getUser.bind(this);
this.error = error.bind(this);
this.log = log.bind(this);
this.getLL = getLL.bind(this);
this.checkIn = checkIn.bind(this);
this.getRecent = getRecent.bind(this);
this.getCheckins = getCheckins.bind(this);
this.addFriendByID = addFriendByID.bind(this);
this.completemultifactorlogin = completemultifactorlogin.bind(this);
this.initiatemultifactorlogin = initiatemultifactorlogin.bind(this);
this.getTrending = getTrending.bind(this);
this.getVenue = getVenue.bind(this);
this.getLastSeen = getLastSeen.bind(this);
this.getGeos = getGeos.bind(this);
this.getUserProfile = getUserProfile.bind(this);
this.login = login.bind(this);
this.register_device = register_device.bind(this);
this.private_log = private_log.bind(this);
this.likeCheckin = likeCheckin.bind(this);
}
// TODO: move to client
async addHereNow(checkin, females_only = true) {
const hereNow = checkin?.venue?.hereNow;
const friendships = [];
if (hereNow?.count > 0) {
console.log(`Found ${hereNow.count} friends from ${checkin.venue.name}...`);
for (const group of hereNow.groups) {
console.log(`${group.count} friends in ${group.name} group...`);
if (group.count > 0) {
const filteredItems = females_only ? group.items.filter((item) => item.user?.gender === "female") : group.items;
const friendNames = filteredItems.map((friend) => `${friend.user.firstName} (${friend.user.handle}) # ${friend.user.id}`);
console.log(`Adding ${filteredItems.length} friends from ${group.name}...`);
console.log(friendNames.join(", "));
const newFriendships = await Promise.all(
filteredItems.map(async (item) => {
return await this.addFriendByID(item.user.id);
})
);
friendships.push(...newFriendships);
console.log(`Added ${newFriendships.length} friends from ${group.name}...`);
console.log(friendNames);
}
}
}
return {
"hereNow": hereNow,
"friendships": friendships
};
}
// auto add trending function
// TODO: maybe move it to the client, not the library
async autoAddTrending(location_name, limit_trending) {
try {
const trending = await this.getTrending(limit_trending, void 0, location_name);
const resultPromises = trending.map(async (venue) => {
if (venue.hereNow.count > 0) {
const checkin = await this.checkIn(venue.id, true);
return this.addHereNow(checkin);
}
return null;
});
const result = await Promise.all(resultPromises);
return result.filter((item) => item !== null);
} catch (error2) {
console.log("An error occurred while auto adding trending:");
this.error("An error occurred:", error2);
return [];
}
}
// TODO: move to client
async likeUnliked(limit = 40) {
try {
const succeeded = [];
const failed = [];
const recent = await this.getRecent(limit);
const likePromises = recent.map(async (checkin) => {
if (!checkin.like) {
try {
const liked_result = await this.likeCheckin(checkin.id);
succeeded.push(liked_result);
} catch (likeError) {
failed.push(checkin.id);
}
} else {
failed.push(checkin.id);
}
});
await Promise.all(likePromises);
return { succeeded, failed };
} catch (error2) {
console.error("An error occurred:", error2);
return { succeeded: [], failed: [] };
}
}
};