biketag
Version:
The Javascript client API for BikeTag Games
1,205 lines • 244 kB
JavaScript
(function(global, factory) {
typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("@aws-sdk/client-s3"), require("tinycache"), require("@aws-sdk/s3-request-presigner"), require("axios"), require("imgur"), require("@sanity/client"), require("axios-cache-interceptor"), require("dequal")) : typeof define === "function" && define.amd ? define(["exports", "@aws-sdk/client-s3", "tinycache", "@aws-sdk/s3-request-presigner", "axios", "imgur", "@sanity/client", "axios-cache-interceptor", "dequal"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.BikeTagClient = {}, global.S3Client, global.TinyCache, global.S3RequestPresigner, global.axios, global.ImgurClient, global.SanityClient, global.axiosCacheInterceptor, global.dequal));
})(this, function(exports2, clientS3, TinyCache, s3RequestPresigner, axios, imgur, client, axiosCacheInterceptor, dequal) {
"use strict";
var AvailableApis = /* @__PURE__ */ ((AvailableApis2) => {
AvailableApis2["biketag"] = "biketag";
AvailableApis2["aws"] = "aws";
AvailableApis2["imgur"] = "imgur";
AvailableApis2["sanity"] = "sanity";
return AvailableApis2;
})(AvailableApis || {});
var DataTypes = /* @__PURE__ */ ((DataTypes2) => {
DataTypes2[DataTypes2["ambassador"] = 0] = "ambassador";
DataTypes2[DataTypes2["game"] = 1] = "game";
DataTypes2[DataTypes2["player"] = 2] = "player";
DataTypes2[DataTypes2["setting"] = 3] = "setting";
DataTypes2[DataTypes2["tag"] = 4] = "tag";
DataTypes2[DataTypes2["queue"] = 5] = "queue";
DataTypes2[DataTypes2["stat"] = 6] = "stat";
DataTypes2[DataTypes2["achievement"] = 7] = "achievement";
return DataTypes2;
})(DataTypes || {});
var GameSettingsKeys = /* @__PURE__ */ ((GameSettingsKeys2) => {
GameSettingsKeys2["achievementsEnabled"] = "achievements::enabled";
return GameSettingsKeys2;
})(GameSettingsKeys || {});
var Errors = /* @__PURE__ */ ((Errors2) => {
Errors2["NotImplemented"] = "method not implemented for adapter: ";
return Errors2;
})(Errors || {});
var HttpStatusCode = /* @__PURE__ */ ((HttpStatusCode2) => {
HttpStatusCode2[HttpStatusCode2["Continue"] = 100] = "Continue";
HttpStatusCode2[HttpStatusCode2["SwitchingProtocols"] = 101] = "SwitchingProtocols";
HttpStatusCode2[HttpStatusCode2["Processing"] = 102] = "Processing";
HttpStatusCode2[HttpStatusCode2["Ok"] = 200] = "Ok";
HttpStatusCode2[HttpStatusCode2["Created"] = 201] = "Created";
HttpStatusCode2[HttpStatusCode2["Accepted"] = 202] = "Accepted";
HttpStatusCode2[HttpStatusCode2["NonAuthoritativeInformation"] = 203] = "NonAuthoritativeInformation";
HttpStatusCode2[HttpStatusCode2["NoContent"] = 204] = "NoContent";
HttpStatusCode2[HttpStatusCode2["ResetContent"] = 205] = "ResetContent";
HttpStatusCode2[HttpStatusCode2["PartialContent"] = 206] = "PartialContent";
HttpStatusCode2[HttpStatusCode2["MultiStatus"] = 207] = "MultiStatus";
HttpStatusCode2[HttpStatusCode2["AlreadyReported"] = 208] = "AlreadyReported";
HttpStatusCode2[HttpStatusCode2["ImUsed"] = 226] = "ImUsed";
HttpStatusCode2[HttpStatusCode2["MultipleChoices"] = 300] = "MultipleChoices";
HttpStatusCode2[HttpStatusCode2["MovedPermanently"] = 301] = "MovedPermanently";
HttpStatusCode2[HttpStatusCode2["Found"] = 302] = "Found";
HttpStatusCode2[HttpStatusCode2["SeeOther"] = 303] = "SeeOther";
HttpStatusCode2[HttpStatusCode2["NotModified"] = 304] = "NotModified";
HttpStatusCode2[HttpStatusCode2["UseProxy"] = 305] = "UseProxy";
HttpStatusCode2[HttpStatusCode2["SwitchProxy"] = 306] = "SwitchProxy";
HttpStatusCode2[HttpStatusCode2["TemporaryRedirect"] = 307] = "TemporaryRedirect";
HttpStatusCode2[HttpStatusCode2["PermanentRedirect"] = 308] = "PermanentRedirect";
HttpStatusCode2[HttpStatusCode2["BadRequest"] = 400] = "BadRequest";
HttpStatusCode2[HttpStatusCode2["Unauthorized"] = 401] = "Unauthorized";
HttpStatusCode2[HttpStatusCode2["PaymentRequired"] = 402] = "PaymentRequired";
HttpStatusCode2[HttpStatusCode2["Forbidden"] = 403] = "Forbidden";
HttpStatusCode2[HttpStatusCode2["NotFound"] = 404] = "NotFound";
HttpStatusCode2[HttpStatusCode2["MethodNotAllowed"] = 405] = "MethodNotAllowed";
HttpStatusCode2[HttpStatusCode2["NotAcceptable"] = 406] = "NotAcceptable";
HttpStatusCode2[HttpStatusCode2["ProxyAuthenticationRequired"] = 407] = "ProxyAuthenticationRequired";
HttpStatusCode2[HttpStatusCode2["RequestTimeout"] = 408] = "RequestTimeout";
HttpStatusCode2[HttpStatusCode2["Conflict"] = 409] = "Conflict";
HttpStatusCode2[HttpStatusCode2["Gone"] = 410] = "Gone";
HttpStatusCode2[HttpStatusCode2["LengthRequired"] = 411] = "LengthRequired";
HttpStatusCode2[HttpStatusCode2["PreconditionFailed"] = 412] = "PreconditionFailed";
HttpStatusCode2[HttpStatusCode2["PayloadTooLarge"] = 413] = "PayloadTooLarge";
HttpStatusCode2[HttpStatusCode2["UriTooLong"] = 414] = "UriTooLong";
HttpStatusCode2[HttpStatusCode2["UnsupportedMediaType"] = 415] = "UnsupportedMediaType";
HttpStatusCode2[HttpStatusCode2["RangeNotSatisfiable"] = 416] = "RangeNotSatisfiable";
HttpStatusCode2[HttpStatusCode2["ExpectationFailed"] = 417] = "ExpectationFailed";
HttpStatusCode2[HttpStatusCode2["IAmATeapot"] = 418] = "IAmATeapot";
HttpStatusCode2[HttpStatusCode2["MisdirectedRequest"] = 421] = "MisdirectedRequest";
HttpStatusCode2[HttpStatusCode2["UnprocessableEntity"] = 422] = "UnprocessableEntity";
HttpStatusCode2[HttpStatusCode2["Locked"] = 423] = "Locked";
HttpStatusCode2[HttpStatusCode2["FailedDependency"] = 424] = "FailedDependency";
HttpStatusCode2[HttpStatusCode2["UpgradeRequired"] = 426] = "UpgradeRequired";
HttpStatusCode2[HttpStatusCode2["PreconditionRequired"] = 428] = "PreconditionRequired";
HttpStatusCode2[HttpStatusCode2["TooManyRequests"] = 429] = "TooManyRequests";
HttpStatusCode2[HttpStatusCode2["RequestHeaderFieldsTooLarge"] = 431] = "RequestHeaderFieldsTooLarge";
HttpStatusCode2[HttpStatusCode2["UnavailableForLegalReasons"] = 451] = "UnavailableForLegalReasons";
HttpStatusCode2[HttpStatusCode2["InternalServerError"] = 500] = "InternalServerError";
HttpStatusCode2[HttpStatusCode2["NotImplemented"] = 501] = "NotImplemented";
HttpStatusCode2[HttpStatusCode2["BadGateway"] = 502] = "BadGateway";
HttpStatusCode2[HttpStatusCode2["ServiceUnavailable"] = 503] = "ServiceUnavailable";
HttpStatusCode2[HttpStatusCode2["GatewayTimeout"] = 504] = "GatewayTimeout";
HttpStatusCode2[HttpStatusCode2["HttpVersionNotSupported"] = 505] = "HttpVersionNotSupported";
HttpStatusCode2[HttpStatusCode2["VariantAlsoNegotiates"] = 506] = "VariantAlsoNegotiates";
HttpStatusCode2[HttpStatusCode2["InsufficientStorage"] = 507] = "InsufficientStorage";
HttpStatusCode2[HttpStatusCode2["LoopDetected"] = 508] = "LoopDetected";
HttpStatusCode2[HttpStatusCode2["NotExtended"] = 510] = "NotExtended";
HttpStatusCode2[HttpStatusCode2["NetworkAuthenticationRequired"] = 511] = "NetworkAuthenticationRequired";
return HttpStatusCode2;
})(HttpStatusCode || {});
const cacheKeys = {
sanityUrlText: `sanity::`,
imageHashText: `hash::`,
albumHash: `album::`,
hintText: `hint::`,
timeText: `time::`,
playerText: `player::`,
playerData: `playerData::`,
playerIdText: `playerId::`,
gameIdText: `gameId::`,
gameSlugText: `slug::`,
gameText: `game::`,
locationText: `location::`,
discussionText: `discussion::`,
mentionText: `mention::`,
tagNumberText: `tag::`,
imagesText: `images::`,
imageUrlText: `imageUrl::`,
gpsStringText: `gpsString::`,
slugText: `slug::`
};
const createTagObject = (tagData = {}, foundTagData = {}) => {
return {
_id: tagData._id,
_type: tagData._type,
/// Common Tag Data
game: tagData.game ?? "",
slug: tagData.slug ?? "",
name: tagData.name ?? "",
playerId: tagData.playerId ?? "",
tagnumber: tagData.tagnumber ?? 0,
/// Mystery Tag Data
mysteryPlayer: tagData.mysteryPlayer ?? "",
mysteryImage: tagData.mysteryImage,
mysteryImageUrl: tagData.mysteryImageUrl ?? "",
mysteryTime: tagData.mysteryTime ?? 0,
hint: tagData.hint ?? "",
discussionUrl: tagData.discussionUrl ?? "",
mentionUrl: tagData.mentionUrl ?? "",
/// Found Tag Data
foundPlayer: foundTagData.foundPlayer ?? tagData.foundPlayer ?? "",
foundImage: foundTagData.foundImage ?? tagData.foundImage,
foundImageUrl: foundTagData.foundImageUrl ?? tagData.foundImageUrl ?? "",
foundTime: foundTagData.foundTime ?? tagData.foundTime ?? 0,
foundLocation: foundTagData.foundLocation ?? tagData.foundLocation ?? "",
confirmedBoundary: foundTagData.confirmedBoundary ?? tagData.confirmedBoundary ?? false,
gps: foundTagData.gps ?? tagData.gps ?? ""
};
};
const tagDataFields = Object.keys(createTagObject());
const tagDataReferenceFields = ["game", "player"];
const tagDataAssetFields = ["foundImage", "mysteryImage"];
const tagDataObjectFields = {
foundImage: "asset->_ref",
mysteryImage: "asset->_ref"
};
const createGameObject = (gameData = {}) => {
return {
_id: gameData._id,
_type: gameData._type,
name: gameData.name ?? gameData.slug ?? "",
ambassadors: gameData.ambassadors ?? [],
settings: gameData.settings ?? [],
boundary: gameData.boundary ?? {},
mainhash: gameData.mainhash ?? "",
archivehash: gameData.archivehash ?? "",
queuehash: gameData.queuehash ?? "",
logo: gameData.logo,
awsRegion: gameData.awsRegion,
region: gameData.region ?? { name: gameData.name },
slug: gameData.slug ?? gameData.name ?? ""
};
};
const gameDataReferenceFields = ["region", "settings"];
const gameDataArrayFields = ["ambassadors", "tags", "settings"];
const gameDataCustomFields = {
settings: "[]->{key,value}",
region: "name,description,zipcode,radius,tz"
};
const gameDataFields = Object.keys(createGameObject());
const gameDataObjectFields = {
logo: "asset->_ref"
};
const createPlayerObject = (playerData = {}) => {
return {
_id: playerData._id,
_type: playerData._type,
achievements: playerData.achievements ?? [],
bicon: playerData.bicon ?? "",
games: playerData.games ?? (playerData.game ? [playerData.game] : []),
name: playerData.name ?? "",
slug: playerData.slug ?? "",
tags: playerData.tags ?? []
};
};
const playerDataFields = Object.keys(createPlayerObject());
const playerDataReferenceFields = ["games", "tags", "achievements"];
const playerDataArrayFields = ["games", "tags", "achievements"];
const playerDataAssetFields = [];
const playerDataObjectFields = {};
const createAmbassadorObject = (ambassadorData = {}) => {
return {
id: ambassadorData._id ?? ambassadorData.id ?? "",
address1: ambassadorData.address1 ?? "",
address2: ambassadorData.address2 ?? "",
city: ambassadorData.city ?? "",
country: ambassadorData.country ?? "",
email: ambassadorData.email ?? "",
name: ambassadorData.name ?? "",
phone: ambassadorData.phone ?? "",
player: ambassadorData.player ?? "",
slug: ambassadorData.slug ?? "",
zipcode: ambassadorData.zipcode ?? ""
};
};
const ambassadorDataFields = Object.keys(createAmbassadorObject());
const ambassadorDataReferenceFields = ["player"];
const createSettingObject = (settingData = {}) => {
return {
slug: settingData.slug ?? "",
description: settingData.description ?? "",
name: settingData.name ?? "",
key: settingData.key ?? "",
value: settingData.value ?? ""
};
};
const settingDataFields = Object.keys(createSettingObject());
const statDataReferenceFields = ["game"];
const statDataArrayFields = [];
const createStatObject = (statData = {}) => {
return {
description: statData.description ?? "",
game: statData.game ?? "",
name: statData.name ?? "",
key: statData.key ?? "",
value: statData.value ?? "",
updatedAt: statData._updatedAt ?? statData._updatedAt ?? /* @__PURE__ */ new Date()
};
};
const statDataFields = [...Object.keys(createStatObject()), "_updatedAt"];
const createAchievementObject = (achievementData = {}) => {
return {
slug: achievementData.slug ?? "",
description: achievementData.description ?? "",
name: achievementData.name ?? "",
key: achievementData.key ?? "",
value: achievementData.value ?? "",
group: achievementData.group ?? ""
};
};
const achievementDataFields = Object.keys(createAchievementObject());
const awsRegions = [
"us-east-1",
"us-east-2",
"us-west-1",
"us-west-2",
"ca-central-1",
"eu-west-1",
"eu-west-2",
"eu-west-3",
"eu-central-1",
"eu-north-1",
"ap-southeast-1",
"ap-southeast-2",
"ap-northeast-1",
"ap-northeast-2",
"ap-south-1",
"sa-east-1"
];
const putCacheIfExists = (key, value, cache) => {
if (cache) cache.put(key, value);
};
const getCacheIfExists = (key, cache) => {
if (cache) return cache.get(key);
return null;
};
const constructTagNumberSlug = (number, game = "") => {
return `${game}-tag-${number}`;
};
const isImgurCredentials = (credentials) => {
return credentials?.clientId !== void 0 || credentials?.clientSecret !== void 0 || credentials?.clientId !== void 0 && credentials?.hash !== void 0;
};
const isImgurApiReady = (credentials) => {
if (!(credentials.clientId || credentials.hash)) {
return 0;
} else if (credentials.accessToken) {
return 3;
} else if (credentials.clientId && credentials.clientSecret) {
return 2;
}
return 1;
};
const isSanityCredentials = (credentials) => {
return credentials?.projectId !== void 0;
};
const isAWSCredentials = (credentials) => {
return !!credentials?.accessKeyId;
};
const isAWSApiReady = (credentials) => {
if (credentials.accessKeyId !== void 0) {
return credentials.secretAccessKey !== void 0 ? 3 : 1;
}
return 0;
};
const isSanityApiReady = (credentials) => {
if (credentials.projectId !== void 0 && credentials.dataset !== void 0 && credentials.apiVersion !== void 0) {
return credentials.token !== void 0 ? 3 : 1;
}
return 0;
};
const isBikeTagCredentials = (credentials) => {
return credentials?.game !== void 0 || credentials?.clientToken !== void 0 && credentials?.clientKey !== void 0;
};
const isBikeTagApiReady = (credentials) => {
return credentials ? 1 : 0;
};
const createImgurCredentials = (credentials, defaults = {}) => {
return {
hash: credentials.hash?.length ? credentials.hash : defaults.hash,
queuehash: credentials.queuehash?.length ? credentials.queuehash : defaults.queuehash,
archivehash: credentials.archivehash?.length ? credentials.archivehash : defaults.archivehash,
clientId: credentials.clientId?.length ? credentials.clientId : defaults.clientId,
clientSecret: credentials.clientSecret?.length ? credentials.clientSecret : defaults.clientSecret,
accessToken: credentials.accessToken?.length ? credentials.accessToken : defaults.accessToken,
refreshToken: credentials.refreshToken?.length ? credentials.refreshToken : defaults.refreshToken,
rapidApiHost: credentials.rapidApiHost?.length ? credentials.rapidApiHost : defaults.rapidApiHost,
rapidApiKey: credentials.rapidApiKey?.length ? credentials.rapidApiKey : defaults.rapidApiKey
};
};
const assignImgurCredentials = (credentials, defaults = {}) => {
const imgurCredentials = isImgurCredentials(credentials) ? createImgurCredentials(credentials, defaults) : defaults;
return imgurCredentials;
};
const createSanityCredentials = (credentials, defaults = {}) => {
return {
useCdn: credentials.token?.length ? false : typeof credentials.useCdn !== "undefined" ? credentials.useCdn : typeof defaults.useCdn !== "undefined" ? defaults.useCdn : true,
projectId: credentials.projectId?.length ? credentials.projectId : defaults.projectId,
dataset: credentials.dataset?.length ? credentials.dataset : defaults.dataset ?? "development",
token: credentials.token?.length ? credentials.token : defaults.token ?? "",
password: credentials.password?.length ? credentials.password : defaults.password,
username: credentials.username?.length ? credentials.username : defaults.username,
apiVersion: credentials.apiVersion?.length ? credentials.apiVersion : defaults.apiVersion ?? "2021-10-21"
};
};
const assignSanityCredentials = (credentials, defaults) => {
const sanityCredentials = isSanityCredentials(
credentials
) ? createSanityCredentials(credentials, defaults) : defaults;
return sanityCredentials;
};
const createAWSCredentials = (credentials, defaults = {}) => {
const region = credentials.region?.length ? credentials.region : defaults.region;
let endpoint = credentials.endpoint?.length ? credentials.endpoint : defaults.endpoint;
if (!endpoint && region && awsRegions.indexOf(region) === -1) {
endpoint = `https://${region}.digitaloceanspaces.com`;
}
return {
accessKeyId: credentials.accessKeyId?.length > 0 ? credentials.accessKeyId : defaults.accessKeyId,
secretAccessKey: credentials.secretAccessKey?.length > 0 ? credentials.secretAccessKey : defaults.secretAccessKey,
region,
endpoint
};
};
const assignAWSCredentials = (credentials, defaults) => {
const awsCredentials = isAWSCredentials(credentials) ? createAWSCredentials(credentials, defaults) : defaults;
return awsCredentials;
};
const createBikeTagCredentials = (credentials, defaults = {}) => {
return {
game: credentials.game?.length ? credentials.game : defaults.game,
host: credentials.host?.length ? credentials.host : defaults.host,
verbose: credentials.verbose,
cached: typeof credentials.cached !== "undefined" ? credentials.cached : defaults.cached,
source: credentials.source?.length ? credentials.source : defaults.source,
clientKey: credentials.clientKey?.length ? credentials.clientKey : defaults.clientKey,
clientToken: credentials.clientToken?.length ? credentials.clientToken : defaults.clientToken
};
};
const assignBikeTagCredentials = (credentials, defaults) => {
const biketagCredentials = isBikeTagCredentials(credentials) ? createBikeTagCredentials(credentials, defaults) : defaults;
return biketagCredentials;
};
const assignBikeTagConfiguration = (config, defaults) => {
const configuration = {};
const parsedConfig = {
biketag: assignBikeTagCredentials(
config,
defaults?.biketag
),
sanity: assignSanityCredentials(
config,
defaults?.sanity
),
aws: assignAWSCredentials(
config,
defaults?.aws
),
imgur: assignImgurCredentials(
config,
defaults?.imgur
)
};
configuration.biketag = config.biketag ? { ...parsedConfig.biketag, ...createBikeTagCredentials(config.biketag) } : parsedConfig.biketag;
configuration.aws = config.aws ? { ...parsedConfig.aws, ...createAWSCredentials(config.aws) } : parsedConfig.aws;
configuration.sanity = config.sanity ? { ...parsedConfig.sanity, ...createSanityCredentials(config.sanity) } : parsedConfig.sanity;
configuration.imgur = config.imgur ? { ...parsedConfig.imgur, ...createImgurCredentials(config.imgur) } : parsedConfig.imgur;
return configuration;
};
const sortTags = (tags, sort = "new", limit = 0, time = "all") => {
let sorted = tags;
switch (sort) {
/// Leaderboard?
case "top":
sorted = tags.sort((a, b) => b.tagnumber - a.tagnumber);
break;
/// Queue
case "relevance":
sorted = tags.sort((a, b) => {
const aHasFoundImage = a?.foundImageUrl?.length;
const aHasMysteryImage = a?.mysteryImageUrl?.length;
const bHasFoundImage = b?.foundImageUrl?.length;
const bHasMysteryImage = b?.mysteryImageUrl?.length;
const aHasBothImages = aHasFoundImage && aHasMysteryImage;
const bHasBothImages = bHasFoundImage && bHasMysteryImage;
const bIsBeforeA = -1;
const aIsBeforeB = 1;
if (!aHasBothImages && !bHasBothImages) {
if (aHasFoundImage && bHasFoundImage) {
return a?.foundTime - b?.foundTime;
} else if (aHasFoundImage) {
return aIsBeforeB;
} else if (bHasFoundImage) {
return aIsBeforeB;
}
} else if (aHasBothImages && bHasBothImages) {
const firstToComplete = a?.mysteryTime - b?.mysteryTime;
return firstToComplete;
} else if (aHasBothImages && !bHasBothImages) {
return bIsBeforeA;
} else if (!aHasBothImages && bHasBothImages) {
return aIsBeforeB;
}
return 0;
});
break;
/// BikeTags
case "new":
sorted = tags.sort((a, b) => b?.tagnumber - a?.tagnumber);
break;
/// BikeTags
case "old":
sorted = tags.sort((a, b) => b?.tagnumber - a?.tagnumber).reverse();
break;
default:
sorted = tags.sort((a, b) => a?.tagnumber - b?.tagnumber);
break;
}
let timeConstraint = 0;
switch (time) {
case "hour":
timeConstraint = 60 * 60 * 1e3;
break;
case "day":
timeConstraint = 60 * 60 * 24 * 1e3;
break;
case "week":
timeConstraint = 60 * 60 * 24 * 7 * 1e3;
break;
}
if (timeConstraint) {
const afterDate = Date.now() - timeConstraint;
sorted = sorted.filter((t) => t.mysteryTime * 1e3 > afterDate);
}
return limit !== 0 ? sorted.slice(0, limit) : sorted;
};
const sortPlayers = (players, sort = "new", limit = 0) => {
let sorted = players;
switch (sort) {
case "top":
sorted = players.sort((a, b) => b.tags.length - a.tags.length);
break;
case "comments":
sorted = players.sort((a, b) => a.name.localeCompare(b.name));
break;
case "new":
sorted = players.reverse();
break;
}
return limit !== 0 ? sorted.slice(0, limit) : sorted;
};
const sortAmbassadors = (ambassadors, sort = "new", limit = 0) => {
const sorter = (a, b) => b.name.localeCompare(a.name);
let sorted = ambassadors;
switch (sort) {
case "top":
sorted = ambassadors.sort(sorter);
break;
case "new":
sorted = ambassadors.reverse();
break;
}
return limit !== 0 ? sorted.slice(0, limit) : sorted;
};
const sortSettings = (settings, sort = "new", limit = 0) => {
let sorted = settings;
switch (sort) {
case "comments":
sorted = settings.sort((a, b) => a.name.localeCompare(b.name));
break;
case "new":
sorted = settings.reverse();
break;
}
return limit !== 0 ? sorted.slice(0, limit) : sorted;
};
const sortStats = (stats, sort = "new", limit = 0) => {
let sorted = stats;
switch (sort) {
case "comments":
sorted = stats.sort((a, b) => a.name.localeCompare(b.name));
break;
case "new":
sorted = stats.reverse();
break;
}
return limit !== 0 ? sorted.slice(0, limit) : sorted;
};
const sortAchievements = (achievements, sort = "new", limit = 0) => {
let sorted = achievements;
switch (sort) {
case "comments":
sorted = achievements.sort((a, b) => a.name.localeCompare(b.name));
break;
case "new":
sorted = achievements.reverse();
break;
}
return limit !== 0 ? sorted.slice(0, limit) : sorted;
};
const getGameAlbumFromCache = async (gameAlbumHash, cache, fallback, useCache = true) => {
const cacheKey = `imgur::${cacheKeys.albumHash}${gameAlbumHash}`;
const existsInCache = getCacheIfExists(cacheKey, useCache ? cache : void 0);
if (existsInCache) {
return existsInCache;
}
if (fallback) {
const putIntoCache = await fallback();
putCacheIfExists(cacheKey, putIntoCache, cache);
return putIntoCache;
}
};
const getTagDate = (time) => new Date(time * 1e3);
const convertMiliseconds = (miliseconds, format) => {
const total_seconds = Math.floor(miliseconds / 1e3);
const total_minutes = Math.floor(total_seconds / 60);
const total_hours = Math.floor(total_minutes / 60);
const days = Math.floor(total_hours / 24);
const seconds = total_seconds % 60;
const minutes = total_minutes % 60;
const hours = total_hours % 24;
switch (format) {
case "s":
return total_seconds;
case "m":
return total_minutes;
case "h":
return total_hours;
case "d":
return days;
default:
return { d: days, h: hours, m: minutes, s: seconds };
}
};
const getLongestTimeBetweenTags = (tags) => {
let longestTimeBetweenTags = 0;
let startDate = null;
let endDate = null;
let previousTag = null;
let staleTagNumber = 0;
const sortedTags = [...tags].reverse();
for (const tag of sortedTags) {
if (previousTag !== null) {
const timeBetweenTags = tag.mysteryTime - previousTag.mysteryTime;
if (timeBetweenTags > longestTimeBetweenTags) {
longestTimeBetweenTags = timeBetweenTags;
startDate = new Date(previousTag.mysteryTime * 1e3);
endDate = new Date(tag.mysteryTime * 1e3);
staleTagNumber = previousTag.tagnumber;
}
}
previousTag = tag;
}
return {
timeBetweenTagsDays: convertMiliseconds(
longestTimeBetweenTags * 1e3,
"d"
),
startDate,
endDate,
staleTagNumber
};
};
const getPlayersWithLongestDailyTagStreakData = (players) => {
let longestStreakDays = 0;
let playerRecord;
const playersData = [];
for (const player of players) {
if (player.name === "") {
console.log(
"Player has no name, and probably no real data. Ignoring player: ",
player
);
continue;
}
const playerLongestStreakData = getTagLongestDailyStreakData(
player.tags
);
if (playerLongestStreakData.longestStreakDaysCount > longestStreakDays) {
longestStreakDays = playerLongestStreakData.longestStreakDaysCount;
}
playerRecord = {
playerName: player.name,
longestStreakData: playerLongestStreakData
};
playersData.push(playerRecord);
}
const longestStreakPlayersData = [];
for (const pd of playersData) {
if (pd.longestStreakData.longestStreakDaysCount >= longestStreakDays) {
longestStreakPlayersData.push(pd);
}
}
return longestStreakPlayersData;
};
const getTagLongestDailyStreakData = (tags) => {
const tagDates = getUniqueTagDates(tags);
tagDates.sort((a, b) => a.getTime() - b.getTime());
let streakDaysCount = 1;
let streakDaysCountLongest = 1;
let streakStartDate = null;
let streakLongestStartDate = null;
let streakEndDate = null;
let previousDate = null;
const oneDay = 24 * 60 * 60 * 1e3;
for (const td of tagDates) {
if (previousDate !== null) {
const tagDateMinusOneDay = /* @__PURE__ */ new Date();
tagDateMinusOneDay.setTime(td.getTime() - oneDay);
if (getIsSameDay(tagDateMinusOneDay, previousDate)) {
streakDaysCount++;
if (streakDaysCount === 2) {
streakStartDate = previousDate;
}
if (streakDaysCount >= streakDaysCountLongest) {
streakLongestStartDate = streakStartDate;
streakDaysCountLongest = streakDaysCount;
streakEndDate = td;
}
} else {
streakDaysCount = 1;
}
} else {
streakStartDate = td;
streakEndDate = td;
}
previousDate = td;
}
const streakData = {
longestStreakDaysCount: streakDaysCountLongest,
longestStreakStartDate: streakDaysCountLongest > 1 ? streakLongestStartDate : null,
longestStreakEndDate: streakDaysCountLongest > 1 ? streakEndDate : null
};
return streakData;
};
const getUniqueTagDates = (tags) => {
const uniqueTagDates = [];
for (const tag of tags) {
if (tag.mysteryTime === 0) {
continue;
}
const tagDate = getTagDate(tag.mysteryTime);
if (uniqueTagDates.length === 0) {
uniqueTagDates.push(tagDate);
} else {
const isAlreadyPresent = uniqueTagDates.some(
(date) => getIsSameDay(date, tagDate)
);
if (!isAlreadyPresent) {
uniqueTagDates.push(tagDate);
}
}
}
return uniqueTagDates;
};
const getIsSameDay = (d1, d2) => {
return d1.getFullYear() === d2.getFullYear() && d1.getMonth() === d2.getMonth() && d1.getDate() === d2.getDate();
};
const getDaysDifference = (d1, d2) => {
const timeDiff = Math.abs(d2.getTime() - d1.getTime());
const oneDay = 24 * 60 * 60 * 1e3;
const diffDays = Math.ceil(timeDiff / oneDay);
return diffDays;
};
const getIsWithinDaysRange = (d1, d2, days) => {
const diffDays = getDaysDifference(d1, d2);
return diffDays <= days;
};
const getGameHighestNumberTagsPerNumberDaysData = (tags, days = 1) => {
let tagsPerNumberDaysHighest = 1;
let previousTagDate = null;
let startDate = null;
let endDate = null;
let tagDatesInRange = [];
let tagIsInRange = false;
let tagsPerNumberDaysData = {
tagCount: tagsPerNumberDaysHighest,
dayCount: days,
startDate: null,
endDate: null
};
const oneDay = 24 * 60 * 60 * 1e3;
const daysBack = [...Array(days).keys()];
const sortedTags = [...tags].reverse();
for (const tag of sortedTags) {
const tagDate = getTagDate(tag.mysteryTime);
if (previousTagDate !== null) {
if (tagDatesInRange.length === 0) {
tagDatesInRange = [previousTagDate];
}
const tagDatesInRangeNew = [...tagDatesInRange];
for (const dayBack of daysBack) {
const daysBackTime = oneDay * dayBack;
const tagDateMinusDayBack = /* @__PURE__ */ new Date();
tagDateMinusDayBack.setTime(tagDate.getTime() - daysBackTime);
for (const tagDateInRange of tagDatesInRange) {
if (getIsWithinDaysRange(tagDateInRange, tagDateMinusDayBack, days)) {
tagDatesInRangeNew.push(tagDate);
tagIsInRange = true;
break;
} else {
const indexNotInRangeDate = tagDatesInRangeNew.indexOf(tagDateInRange);
tagDatesInRangeNew.splice(indexNotInRangeDate, 1);
tagIsInRange = false;
}
}
if (tagIsInRange) {
break;
}
}
tagDatesInRange = tagDatesInRangeNew;
if (tagDatesInRange.length >= tagsPerNumberDaysHighest) {
tagsPerNumberDaysHighest = tagDatesInRange.length;
startDate = tagDatesInRange[0];
endDate = tagDatesInRange[tagDatesInRange.length - 1];
}
}
previousTagDate = tagDate;
}
tagsPerNumberDaysData = {
tagCount: tagsPerNumberDaysHighest,
dayCount: days,
startDate,
endDate
};
return tagsPerNumberDaysData;
};
const getPlayerHighestNumberTagsPerDayData = (player) => {
const tagsPerDayData = {
playerName: player.name,
tagCount: null,
tagDate: null
};
let tagsPerDay = 1;
let tagsPerDayHighest = 1;
let previousTagDate = null;
for (const tag of player.tags) {
const tagDate = getTagDate(tag.mysteryTime);
if (previousTagDate !== null && getIsSameDay(tagDate, previousTagDate)) {
tagsPerDay++;
} else {
tagsPerDay = 1;
}
if (tagsPerDay > tagsPerDayHighest) {
tagsPerDayHighest = tagsPerDay;
tagsPerDayData.tagCount = tagsPerDayHighest;
tagsPerDayData.tagDate = tagDate;
}
previousTagDate = tagDate;
}
return tagsPerDayData;
};
const getPlayersWithHighestNumberTagsPerDayData = (players) => {
let tagsPerDayHighest = 0;
const tagsPerDayData = [];
const highestTagsPerDayData = [];
for (const player of players) {
if (player.name === "") {
console.log(
"Player has no name, and probably no real data. Ignoring player: ",
player
);
continue;
}
const tagsPerDayRecord = getPlayerHighestNumberTagsPerDayData(player);
tagsPerDayData.push(tagsPerDayRecord);
if (tagsPerDayRecord.tagCount !== null && tagsPerDayRecord.tagCount > tagsPerDayHighest) {
tagsPerDayHighest = tagsPerDayRecord.tagCount;
}
}
for (const tpdr of tagsPerDayData) {
if (tpdr.tagCount !== null && tpdr.tagCount >= tagsPerDayHighest) {
highestTagsPerDayData.push(tpdr);
}
}
return highestTagsPerDayData;
};
const getExtensionFromUrl = (url) => {
const match = url.match(/\.([a-zA-Z0-9]+)(?:\?|#|$)/);
return match ? match[1].toLowerCase() : void 0;
};
const getImageExtension = (contentType) => {
const imageMimeToExt = {
"image/jpeg": "jpg",
"image/png": "png",
"image/gif": "gif",
"image/webp": "webp",
"image/bmp": "bmp",
"image/avif": "avif",
"image/tiff": "tiff"
};
return imageMimeToExt[contentType.toLowerCase()];
};
const getContentTypeFromExtension = (ext) => {
const extToMime = {
jpg: "image/jpeg",
jpeg: "image/jpeg",
png: "image/png",
gif: "image/gif",
webp: "image/webp",
bmp: "image/bmp",
avif: "image/avif",
tiff: "image/tiff"
};
return extToMime[ext.toLowerCase()] ?? "application/octet-stream";
};
const getTagNumbersFromTextRegex = new RegExp(
/((?:(?:bike\s*)?(?:\s*tag)?)(#|num|number)(\d+)(?:(?:\s*tag)?|(?:\s*proof)?))|((?:bike\s*)?(?:tag\s*)(#|num|number)?\s*(\d+))|((?:(?:found\s*#?)|(?:here'?i?s?\s*))\[?(\d+)\]?)/gi
);
const getPlayerFromTextRegex = new RegExp(
/((?:proof\s*(?:found\s*at\s*)?(?:\(.*\))?\s*by\s*)(.*?(?= on \[|$)))|((?:tag\s*(?:(?:\(\s*hint:\s*)?.*\))?\s*by\s*)(.+?(?= on \[|\r|\n|$))?)|((?:tag\s*(?:(?:\(\s*hint:\s*)?.*\))?\s*by\s*)(.+?(?= on \[|\r|\n))?)|((?:credit goes to:\s*)(.*)(?:\sfor finding))|(?:tag\s*)(?:number\s*)?(\d*)?(?:\s*by\s*)(.+?(?= on \[|$|\n))/i
);
const getFoundLocationFromTextRegex = new RegExp(
/(?:is\s*(?:at|the)?\s*?)(.*?)(?=\s*by\s+|\]|$)|(?:found)\s*(?:at)?\s*\(([^()]+(\([^()]+\)[^()]*)*)\)(.*(?:\)|]|$))|(?:found\s*at\s*\()(.*(?:\)))/im
);
const getConfirmedBoundaryFromTextRegex = new RegExp(
/(\s*\[.*\]✓\s*\(.*\)\s*)/im
);
const getPlayerFromInfoFromTextRegex = new RegExp(
/(?:\[Player\s*)(.*)(?:]\s*\+\()(.*)(?=\))/i
);
const getGameFromInfoFromTextRegex = new RegExp(
/(((?:{\s*)(.*)(?:}))((?:\s*\[)(.*)(?=\])\])?((?:\s*@\()(.*)(?=\))\))?)\s*::\s*(((?:\[BikeTag\s*Game\s*)(.*)(?:]))((?:\s*#\()(.*)(?=\))\))?((?:\s*\|)(.*)(?=\|)\|)?)/i
);
const getGameSlugFromTextRegex = new RegExp(/((\w*)\s*bike\s*tag!?)/i);
const getHintFromTextRegex = new RegExp(/(?:hint:\s*)(.*)\)/i);
const getTimeFromTextRegex = new RegExp(
/(?:on\s+\[(\d+\/\d+\/\d\d)@(\d+:\d+:\d+)\])/i
);
const getGPSLocationFromTextRegex = new RegExp(
/(([0-9]{1,2})[:|°]([0-9]{1,2})[:|'|′]?([0-9]{1,2}(?:\.[0-9]+){0,1})?["|″]([N|S]),?\s*([0-9]{1,3})[:|°]([0-9]{1,2})[:|'|′]?([0-9]{1,2}(?:\.[0-9]+){0,1})?["|″]([E|W]))|((-?\d+(\.\d+)?),\s*(-?\d+(\.\d+)?))/
);
const getImageURLsFromTextRegex = new RegExp(
/https?:\/\/.*?\.[a-z]{2,4}\/.+?(?=\)|\s|$)/gi
);
const getAlbumIdFromTextRegex = new RegExp(
/((?:imgur.com\/)(?:(a|album|gallery)\/)(\w+))/i
);
const getPlayerIdFromTextRegex = RegExp(/\[(.*)\]/i);
const getDiscussionUrlFromTextRegex = RegExp(/{(.*)}/i);
const getGPSCoordinatesValueFromTextRegex = RegExp(/\((.*)\)/i);
const getTagnumberFromSlugRegex = RegExp(/([^-]*)([^-]*)(\d)/);
const getImgurImageHashFromUrlRegex = RegExp(
/(?:imgur.com\/)(.*)(?:\.)/i
);
const getSanityImageUrlHashFromTextRegex = RegExp(
/^(?:image-)(.*?(?=-(-png|-jpg|-jpeg|-gif)))/i
);
const getCreditFromBlueskyTextRegex = RegExp(
/(?:tag\s*)(?:number\s*)?(\d*)?(?:\s*by\s*)(.+?(?=$|\n))/i
);
const isMysteryImageRegex = /^#\d+\s+tag\s*\(.*?\)\s+by\s+.+/i;
const isFoundImageRegex = /^#\d+\s+proof\s+found\s+at\s*\(.*?\)\s+by\s+.+/i;
const isFoundImageFallbackRegex = /^#\d+\s+proof\s+found\s+at\s*\(.*$/i;
const BikeTagExpressions = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
__proto__: null,
getAlbumIdFromTextRegex,
getConfirmedBoundaryFromTextRegex,
getCreditFromBlueskyTextRegex,
getDiscussionUrlFromTextRegex,
getFoundLocationFromTextRegex,
getGPSCoordinatesValueFromTextRegex,
getGPSLocationFromTextRegex,
getGameFromInfoFromTextRegex,
getGameSlugFromTextRegex,
getHintFromTextRegex,
getImageURLsFromTextRegex,
getImgurImageHashFromUrlRegex,
getPlayerFromInfoFromTextRegex,
getPlayerFromTextRegex,
getPlayerIdFromTextRegex,
getSanityImageUrlHashFromTextRegex,
getTagNumbersFromTextRegex,
getTagnumberFromSlugRegex,
getTimeFromTextRegex,
isFoundImageFallbackRegex,
isFoundImageRegex,
isMysteryImageRegex
}, Symbol.toStringTag, { value: "Module" }));
function getTagNumbersFromText$1(inputText, fallback = null, cache) {
if (!inputText?.length) return fallback;
const cacheKey = `${cacheKeys.tagNumberText}${inputText}`;
const existingParsed = getCacheIfExists(cacheKey, cache);
if (existingParsed) return existingParsed;
const tagNumberText = inputText.match(getTagNumbersFromTextRegex);
if (!tagNumberText) return fallback ?? [];
const tagNumbers = tagNumberText.reduce((numbers, text) => {
if (!text) return numbers;
let tagNumber = text.match(/\d+/);
tagNumber = tagNumber?.length ? tagNumber[0] : null;
if (!tagNumber) return numbers;
const number = Number.parseInt(tagNumber);
if (numbers.indexOf(number) == -1) numbers.push(number);
return numbers;
}, []);
if (!tagNumbers.length && fallback) {
putCacheIfExists(cacheKey, fallback, cache);
return fallback;
}
putCacheIfExists(cacheKey, tagNumbers, cache);
return tagNumbers;
}
function getPlayerDataFromText(inputText, cache) {
if (!inputText) return void 0;
const cacheKey = `${cacheKeys.playerData}${inputText}`;
const existingParsed = getCacheIfExists(cacheKey, cache);
if (existingParsed) return existingParsed;
const playerData = getPlayerFromInfoFromTextRegex.exec(inputText);
if (!playerData?.length) return void 0;
const player = createPlayerObject({
name: playerData[1],
games: playerData[2].split(",")
});
if (!player.name?.length) {
putCacheIfExists(cacheKey, false, cache);
return void 0;
}
putCacheIfExists(cacheKey, player, cache);
return player;
}
function getGameSlugFromText(inputText, cache) {
if (!inputText) return void 0;
const cacheKey = `${cacheKeys.gameSlugText}${inputText}`;
const existingParsed = getCacheIfExists(cacheKey, cache);
if (existingParsed) return existingParsed;
const gameData = getGameSlugFromTextRegex.exec(inputText);
if (!gameData?.length) return void 0;
const gameName = gameData[2];
if (!gameName) {
putCacheIfExists(cacheKey, false, cache);
return void 0;
}
putCacheIfExists(cacheKey, gameName, cache);
return gameName;
}
function getGameDataFromText(inputText, cache) {
if (!inputText) return void 0;
const cacheKey = `${cacheKeys.gameText}${inputText}`;
const existingParsed = getCacheIfExists(cacheKey, cache);
if (existingParsed) return existingParsed;
const gameData = getGameFromInfoFromTextRegex.exec(inputText);
if (!gameData?.length) return void 0;
const game = createGameObject({
name: gameData[10],
ambassadors: (gameData[12] ?? "").split(","),
queuehash: gameData[14],
region: { name: gameData[10], description: gameData[3] },
subreddit: gameData[5],
bluesky: gameData[7]
});
if (!game.name?.length) {
putCacheIfExists(cacheKey, false, cache);
return void 0;
}
putCacheIfExists(cacheKey, game, cache);
return game;
}
function getPlayerFromText$1(inputText, fallback, cache) {
if (!inputText) return null;
const cacheKey = `${cacheKeys.playerText}${inputText}`;
const existingParsed = getCacheIfExists(cacheKey, cache);
if (existingParsed) return existingParsed;
const playerText = getPlayerFromTextRegex.exec(inputText);
if (!playerText) return null;
const tagPlayers = playerText.filter(
(c) => typeof c === "string" && (c.indexOf("tag ") === -1 || c.indexOf("tag") !== 0) && (c.indexOf("proof ") === -1 || c.indexOf("proof") !== 0) && c.indexOf("to:") === -1 && c.indexOf("hint:") === -1 && (c.indexOf(" by ") === -1 || c.indexOf(" by ") !== 0) ? c : void 0
);
if (!tagPlayers?.length && fallback) ;
const player = tagPlayers[0];
putCacheIfExists(cacheKey, player, cache);
return player;
}
function getPlayerIdFromText(inputText, fallback, cache) {
if (!inputText?.length) {
return fallback;
}
const cacheKey = `${cacheKeys.playerIdText}${inputText}`;
const existingParsed = getCacheIfExists(cacheKey, cache);
if (existingParsed) return existingParsed;
const playerIdText = getPlayerIdFromTextRegex.exec(inputText);
if (!playerIdText) {
return fallback;
}
const playerId = (playerIdText[1] || "").trim();
putCacheIfExists(cacheKey, playerId, cache);
return playerId;
}
function getDiscussionUrlFromText$1(inputText, fallback, cache) {
if (!inputText?.length) {
return fallback;
}
const cacheKey = `${cacheKeys.discussionText}${inputText}`;
const existingParsed = getCacheIfExists(cacheKey, cache);
if (existingParsed) return existingParsed;
const discussionUrlText = getDiscussionUrlFromTextRegex.exec(inputText);
if (!discussionUrlText) {
putCacheIfExists(cacheKey, fallback, cache);
return fallback;
}
const discussionUrl = (discussionUrlText[1] || "").trim();
putCacheIfExists(cacheKey, discussionUrl, cache);
return discussionUrl;
}
function getFoundLocationFromText$1(inputText, fallback, cache) {
if (!inputText?.length) {
return fallback;
}
const cacheKey = `${cacheKeys.locationText}${inputText}`;
const existingParsed = getCacheIfExists(cacheKey, cache);
if (existingParsed) return existingParsed;
const foundLocationText = getFoundLocationFromTextRegex.exec(inputText);
if (!foundLocationText) {
putCacheIfExists(cacheKey, fallback, cache);
return fallback;
}
const foundLocation = (foundLocationText[1] ?? foundLocationText[2] ?? "").trim();
putCacheIfExists(cacheKey, foundLocation, cache);
return foundLocation;
}
function getConfirmedBoundaryFromText(inputText, fallback, cache) {
if (!inputText?.length) {
return fallback;
}
const cacheKey = `${cacheKeys.locationText}${inputText}`;
const existingParsed = getCacheIfExists(cacheKey, cache);
if (existingParsed) return existingParsed;
const confirmedBoundaryText = getConfirmedBoundaryFromTextRegex.exec(inputText);
if (!confirmedBoundaryText) {
putCacheIfExists(cacheKey, fallback, cache);
return fallback;
}
const confirmedBoundary = (confirmedBoundaryText[4] || "").trim();
putCacheIfExists(cacheKey, confirmedBoundary, cache);
return confirmedBoundary;
}
function getTimeFromText(inputText, fallback, cache) {
const cacheKey = `${cacheKeys.timeText}${inputText}`;
const existingParsed = getCacheIfExists(cacheKey, cache);
if (existingParsed) return existingParsed;
const timeMatch = getTimeFromTextRegex.exec(inputText);
if (!timeMatch || timeMatch?.length < 2) {
fallback = fallback ?? null;
return fallback;
}
const time = (/* @__PURE__ */ new Date(`${timeMatch[1]} ${timeMatch[2]}`)).getTime() / 1e3;
putCacheIfExists(cacheKey, time, cache);
return time;
}
function getHintFromText$1(inputText, fallback, cache) {
const cacheKey = `${cacheKeys.hintText}${inputText}`;
const existingParsed = getCacheIfExists(cacheKey, cache);
if (existingParsed) return existingParsed;
const hintMatch = getHintFromTextRegex.exec(inputText);
if (!hintMatch) {
fallback = fallback ?? null;
putCacheIfExists(cacheKey, fallback, cache);
return fallback;
}
const hint = (hintMatch[1] || "").trim();
putCacheIfExists(cacheKey, hint, cache);
return hint;
}
function getBikeTagNumberFromImage(image, cache) {
return image.description ? getTagNumbersFromText$1(image.description, void 0, cache)[0] : -1;
}
function isMysteryImage$1(image) {
const description = image.description || "";
return isMysteryImageRegex.test(description);
}
function isFoundImage$1(image) {
const description = image.description || "";
if (isFoundImageRegex.test(description)) return true;
return isFoundImageFallbackRegex.test(description);
}
function getBikeTagFromImgurImageSet(mysteryImage, foundImage, opts) {
if (!foundImage && !mysteryImage) return null;
let foundImageLink;
let foundImageDescription;
let foundImageTitle;
let foundTime;
let mysteryImageLink;
let mysteryImageDescription;
let mysteryImageTitle;
let mysteryTime;
let hint;
let discussionUrl;
let mysteryPlayer;
let foundPlayer;
let foundLocation;
let confirmedBoundary;
if (foundImage) {
foundImageLink = foundImage?.link;
foundImageDescription = foundImage?.description;
foundImageTitle = foundImage?.title;
foundTime = getTimeFromText(foundImageDescription, foundImage?.datetime);
foundPlayer = getPlayerFromText$1(foundImageDescription);
foundLocation = getFoundLocationFromText$1(foundImageDescription);
confirmedBoundary = getConfirmedBoundaryFromText(foundImageTitle);
}
if (mysteryImage) {
mysteryImageLink = mysteryImage?.link;
mysteryImageDescription = mysteryImage?.description;
mysteryImageTitle = mysteryImage?.title;
mysteryTime = getTimeFromText(
mysteryImageDescription,
mysteryImage?.datetime
);
hint = getHintFromText$1(mysteryImageDescription);
discussionUrl = getDiscussionUrlFromText$1(mysteryImageTitle);
mysteryPlayer = getPlayerFromText$1(mysteryImageDescription);
}
const game = opts?.game || "";
const tagnumber = mysteryImageDescription ? getTagNumbersFromText$1(mysteryImageDescription)[0] : getTagNumbersFromText$1(foundImageDescription)[0];
const name = constructTagNumberSlug(tagnumber, game);
const playerId = getPlayerIdFromText(mysteryImageTitle) ?? getPlayerIdFromText(foundImageTitle);
let gps = foundImageDescription ? getGPSLocationFromText(foundImageDescription) : getGPSLocationFromText(mysteryImageTitle);
if (gps.lat === 0 && gps.long === 0 && foundImageTitle) {
gps = getGPSLocationFromText(foundImageTitle);
}
if (foundLocation?.length && gps.lat !== 0 && gps.long !== 0) {
const gpsFromFoundLocation = getGpsStringLocationFromText(foundLocation, "");
foundLocation = foundLocation.replace(gpsFromFoundLocation, "").replace(
gpsFromFoundLocation.substring(0, gpsFromFoundLocation.length - 3),
""
);
}
const tagData = {
tagnumber,
name,
slug: name,
game,
discussionUrl,
foundLocation,
mysteryPlayer,
foundPlayer,
foundTime,
mysteryTime,
hint,
playerId,
confirmedBoundary,
mysteryImageUrl: mysteryImageLink,
foundImageUrl: foundImageLink,
/// TODO: get found location gps from found tag
gps
};
return tagData;
}
const getImageHashFromImgurImage = (image, cache) => {
return getImageHashFromText(image.link, cache);
};
const isValidUpdatePayload$3 = (utp) => {
return typeof utp.imageHash === "string" && (typeof utp.title === "string" || typeof utp.description === "string") || typeof utp.title === "string" || typeof utp.description === "string";
};
const isValidUploadTagImagePayload = (utp) => {
return (
/// TODO: do better type checking here
utp && typeof utp.image !== "undefined" && (typeof utp.title === "string" || typeof utp.description === "string")
);
};
const getUpdateTagPayloadFromTagData = (payload, mystery = false, combined = false) => {
return {
imageHash: mystery ? getImgurMysteryImageHashFromBikeTagData(payload) : getImgurFoundImageHashFromBikeTagData(payload),
title: mystery ? getImgurMysteryTitleFromBikeTagData(payload, combined) : getImgurFoundTitleFromBikeTagData(payload, combined),
description: mystery ? getImgurMysteryDescriptionFromBikeTagData(payload) : getImgurFoundDescriptionFromBikeTagData(payload)
};
};
function getQueueTagImagePayloadFromTagData(tagData, mystery = false) {
return {
album: tagData.queuehash ?? tagData.hash,
type: tagData.type ?? "stream",
image: mystery ? tagData.mysteryImage : tagData.foundImage,
title: tagData.title ?? (myste