UNPKG

@flowdegree/swarmapp-api

Version:

A javascript wrapper for swarmapp (foursquare) API

556 lines (546 loc) 19 kB
"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: [] }; } } };