Merge pull request #9 from Invest-Bot/dev
Merge Dev: Literally the entire userpage and FFZ/BTTV/TTV APIs
This commit is contained in:
commit
653bac9a99
22 changed files with 2647 additions and 376 deletions
|
@ -24,7 +24,7 @@ function NavBar() {
|
||||||
variants={navIconVariants}
|
variants={navIconVariants}
|
||||||
className="pr-5 lg:pr-0 lg:pt-3 lg:pb-3"
|
className="pr-5 lg:pr-0 lg:pt-3 lg:pb-3"
|
||||||
>
|
>
|
||||||
<ActiveLink href="/dashboard/ranking">
|
<ActiveLink href="/ranking">
|
||||||
<RankingIcon />
|
<RankingIcon />
|
||||||
</ActiveLink>
|
</ActiveLink>
|
||||||
</m.div>
|
</m.div>
|
||||||
|
|
|
@ -8,7 +8,6 @@ import {
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import NavBar from "../components/dashboard/NavBar";
|
import NavBar from "../components/dashboard/NavBar";
|
||||||
import { NavTemplate } from "./NavTemplates";
|
|
||||||
|
|
||||||
interface DashLayoutProps {
|
interface DashLayoutProps {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
|
@ -26,6 +25,7 @@ function DashLayout(props: DashLayoutProps) {
|
||||||
variants={containerVariants}
|
variants={containerVariants}
|
||||||
>
|
>
|
||||||
<Head>
|
<Head>
|
||||||
|
<meta name="viewport" content="initial-scale=0.8" />
|
||||||
<title>Dashboard - toffee</title>
|
<title>Dashboard - toffee</title>
|
||||||
<meta name="description" content="Dashboard statistics for toffee" />
|
<meta name="description" content="Dashboard statistics for toffee" />
|
||||||
<link rel="icon" href="/favicon.ico" />
|
<link rel="icon" href="/favicon.ico" />
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import Redis from "ioredis";
|
import type RedisInstance from "ioredis";
|
||||||
|
|
||||||
let redis = new Redis(process.env.REDIS_URL);
|
|
||||||
|
|
||||||
async function applyCache(
|
async function applyCache(
|
||||||
|
redis: RedisInstance,
|
||||||
key: string,
|
key: string,
|
||||||
query: string,
|
query: string,
|
||||||
gql: boolean,
|
gql: boolean,
|
||||||
|
@ -11,7 +10,7 @@ async function applyCache(
|
||||||
if (await redis.get(key)) {
|
if (await redis.get(key)) {
|
||||||
return JSON.parse((await redis.get(key)) as string);
|
return JSON.parse((await redis.get(key)) as string);
|
||||||
} else {
|
} else {
|
||||||
const response = await fetchEndpoint(query, gql);
|
const response = await fetchEndpoint(redis, query, gql);
|
||||||
if (response != null) {
|
if (response != null) {
|
||||||
await redis.set(key, JSON.stringify(response), "EX", cacheTime);
|
await redis.set(key, JSON.stringify(response), "EX", cacheTime);
|
||||||
}
|
}
|
||||||
|
@ -19,7 +18,11 @@ async function applyCache(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchEndpoint(query: string, gql: boolean = false) {
|
async function fetchEndpoint(
|
||||||
|
redis: RedisInstance,
|
||||||
|
query: string,
|
||||||
|
gql: boolean = false
|
||||||
|
) {
|
||||||
if (await redis.get("7TV.RATE_LIMIT")) {
|
if (await redis.get("7TV.RATE_LIMIT")) {
|
||||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||||
} else {
|
} else {
|
||||||
|
@ -50,7 +53,7 @@ async function fetchGQL(query: string) {
|
||||||
return json;
|
return json;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getGlobalEmotes() {
|
async function getGlobalEmotes(redis: RedisInstance) {
|
||||||
const gqlQuery = `query {
|
const gqlQuery = `query {
|
||||||
namedEmoteSet(name: GLOBAL) {
|
namedEmoteSet(name: GLOBAL) {
|
||||||
emote_count
|
emote_count
|
||||||
|
@ -78,10 +81,10 @@ async function getGlobalEmotes() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}`;
|
}`;
|
||||||
return await applyCache("7TV.GLOBAL_EMOTES", gqlQuery, true, 3600);
|
return await applyCache(redis, "7TV.GLOBAL_EMOTES", gqlQuery, true, 3600);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getChannelEmotes(channelID: string) {
|
async function getChannelEmotes(redis: RedisInstance, channelID: string) {
|
||||||
const gqlQuery = `query {
|
const gqlQuery = `query {
|
||||||
user(id: "${channelID}") {
|
user(id: "${channelID}") {
|
||||||
emote_sets {
|
emote_sets {
|
||||||
|
@ -112,6 +115,7 @@ async function getChannelEmotes(channelID: string) {
|
||||||
}
|
}
|
||||||
}`;
|
}`;
|
||||||
return await applyCache(
|
return await applyCache(
|
||||||
|
redis,
|
||||||
"7TV.CHANNEL_EMOTES_" + channelID,
|
"7TV.CHANNEL_EMOTES_" + channelID,
|
||||||
gqlQuery,
|
gqlQuery,
|
||||||
true,
|
true,
|
||||||
|
|
58
misc/BTTVAPI.tsx
Normal file
58
misc/BTTVAPI.tsx
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
import type RedisInstance from "ioredis";
|
||||||
|
|
||||||
|
async function applyCache(
|
||||||
|
redis: RedisInstance,
|
||||||
|
key: string,
|
||||||
|
query: string,
|
||||||
|
|
||||||
|
cacheTime: number
|
||||||
|
) {
|
||||||
|
if (await redis.get(key)) {
|
||||||
|
return JSON.parse((await redis.get(key)) as string);
|
||||||
|
} else {
|
||||||
|
const response = await fetchEndpoint(redis, query);
|
||||||
|
if (response != null) {
|
||||||
|
await redis.set(key, JSON.stringify(response), "EX", cacheTime);
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchEndpoint(redis: RedisInstance, query: string) {
|
||||||
|
if (await redis.get("BTTV.RATE_LIMIT")) {
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||||
|
} else {
|
||||||
|
await redis.set("BTTV.RATE_LIMIT", "1", "EX", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const requestHeaders = new Headers();
|
||||||
|
requestHeaders.append("Content-Type", "application/json");
|
||||||
|
requestHeaders.append("User-Agent", "toffee-web/indev");
|
||||||
|
|
||||||
|
const response = await fetch(query, {
|
||||||
|
headers: requestHeaders,
|
||||||
|
});
|
||||||
|
|
||||||
|
const json = await response.json();
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getGlobalEmotes(redis: RedisInstance) {
|
||||||
|
return await applyCache(
|
||||||
|
redis,
|
||||||
|
"BTTV.GLOBAL_EMOTES",
|
||||||
|
"https://api.betterttv.net/3/cached/emotes/global",
|
||||||
|
3600
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getUserByID(redis: RedisInstance, channelID: string) {
|
||||||
|
return await applyCache(
|
||||||
|
redis,
|
||||||
|
`BTTV.CHANNEL_EMOTES.${channelID}`,
|
||||||
|
`https://api.betterttv.net/3/cached/users/twitch/${channelID}`,
|
||||||
|
3600
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { getGlobalEmotes, getUserByID };
|
58
misc/FFZAPI.tsx
Normal file
58
misc/FFZAPI.tsx
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
import type RedisInstance from "ioredis";
|
||||||
|
|
||||||
|
async function applyCache(
|
||||||
|
redis: RedisInstance,
|
||||||
|
key: string,
|
||||||
|
query: string,
|
||||||
|
|
||||||
|
cacheTime: number
|
||||||
|
) {
|
||||||
|
if (await redis.get(key)) {
|
||||||
|
return JSON.parse((await redis.get(key)) as string);
|
||||||
|
} else {
|
||||||
|
const response = await fetchEndpoint(redis, query);
|
||||||
|
if (response != null) {
|
||||||
|
await redis.set(key, JSON.stringify(response), "EX", cacheTime);
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchEndpoint(redis: RedisInstance, query: string) {
|
||||||
|
if (await redis.get("FFZ.RATE_LIMIT")) {
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||||
|
} else {
|
||||||
|
await redis.set("FFZ.RATE_LIMIT", "1", "EX", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const requestHeaders = new Headers();
|
||||||
|
requestHeaders.append("Content-Type", "application/json");
|
||||||
|
requestHeaders.append("User-Agent", "toffee-web/indev");
|
||||||
|
|
||||||
|
const response = await fetch(query, {
|
||||||
|
headers: requestHeaders,
|
||||||
|
});
|
||||||
|
|
||||||
|
const json = await response.json();
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getGlobalEmotes(redis: RedisInstance) {
|
||||||
|
return await applyCache(
|
||||||
|
redis,
|
||||||
|
"FFZ.GLOBAL_EMOTES",
|
||||||
|
"https://api.frankerfacez.com/v1/set/global",
|
||||||
|
3600
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getEmoteSet(redis: RedisInstance, setID: string) {
|
||||||
|
return await applyCache(
|
||||||
|
redis,
|
||||||
|
`FFZ.EMOTE_SET.${setID}`,
|
||||||
|
`https://api.frankerfacez.com/v1/set/${setID}`,
|
||||||
|
3600
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { getGlobalEmotes, getEmoteSet };
|
94
misc/TwitchAPI.tsx
Normal file
94
misc/TwitchAPI.tsx
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
import RedisInstance from "ioredis";
|
||||||
|
|
||||||
|
async function applyCache(
|
||||||
|
redis: RedisInstance,
|
||||||
|
key: string,
|
||||||
|
query: string,
|
||||||
|
cacheTime: number
|
||||||
|
) {
|
||||||
|
if (await redis.get(key)) {
|
||||||
|
return JSON.parse((await redis.get(key)) as string);
|
||||||
|
} else {
|
||||||
|
const response = await fetchEndpoint(redis, query);
|
||||||
|
if (response != null) {
|
||||||
|
await redis.set(key, JSON.stringify(response), "EX", cacheTime);
|
||||||
|
}
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function authTwitch(redis: RedisInstance) {
|
||||||
|
let auth = await redis.get("TWITCH.AUTH");
|
||||||
|
if (auth) {
|
||||||
|
return auth;
|
||||||
|
} else {
|
||||||
|
const response = await fetch(
|
||||||
|
`https://id.twitch.tv/oauth2/token?client_id=${process.env.TWITCH_CLIENT_ID}&client_secret=${process.env.TWITCH_SECRET}&grant_type=client_credentials`,
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const json = await response.json();
|
||||||
|
await redis.set("TWITCH.OAUTH", json.access_token, "EX", json.expires_in);
|
||||||
|
|
||||||
|
return json.access_token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function fetchEndpoint(redis: RedisInstance, query: string) {
|
||||||
|
if (await redis.get("TWITCH.RATE_LIMIT")) {
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||||
|
} else {
|
||||||
|
await redis.set("TWITCH.RATE_LIMIT", "1", "EX", 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auth = await authTwitch(redis);
|
||||||
|
|
||||||
|
const requestHeaders = new Headers();
|
||||||
|
requestHeaders.append("Client-ID", process.env.TWITCH_CLIENT_ID ?? "");
|
||||||
|
requestHeaders.append("Authorization", `Bearer ${auth}`);
|
||||||
|
|
||||||
|
const response = await fetch(query, {
|
||||||
|
headers: requestHeaders,
|
||||||
|
});
|
||||||
|
const json = await response.json();
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getUserByName(redis: RedisInstance, username: string) {
|
||||||
|
return await applyCache(
|
||||||
|
redis,
|
||||||
|
"TWITCH.USER_" + username,
|
||||||
|
`https://api.twitch.tv/helix/users?login=${username}`,
|
||||||
|
600
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getUserByID(redis: RedisInstance, userID: string) {
|
||||||
|
return await applyCache(
|
||||||
|
redis,
|
||||||
|
"TWITCH.USER_" + userID,
|
||||||
|
`https://api.twitch.tv/helix/users?id=${userID}`,
|
||||||
|
600
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getGlobalEmotes(redis: RedisInstance) {
|
||||||
|
return await applyCache(
|
||||||
|
redis,
|
||||||
|
"TWITCH.GLOBAL_EMOTES",
|
||||||
|
`https://api.twitch.tv/helix/chat/emotes/global`,
|
||||||
|
3600
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getChannelEmotes(redis: RedisInstance, channelID: string) {
|
||||||
|
return await applyCache(
|
||||||
|
redis,
|
||||||
|
"TWITCH.CHANNEL_EMOTES_" + channelID,
|
||||||
|
`https://api.twitch.tv/helix/chat/emotes?broadcaster_id=${channelID}`,
|
||||||
|
600
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export { getUserByName, getUserByID, getGlobalEmotes, getChannelEmotes };
|
55
misc/redis.ts
Normal file
55
misc/redis.ts
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
// https://makerkit.dev/blog/tutorials/nextjs-redis (I got tired of having redis issues)
|
||||||
|
import Redis, { RedisOptions } from "ioredis";
|
||||||
|
|
||||||
|
const configuration = {
|
||||||
|
redis: {
|
||||||
|
host: process.env.REDIS_HOST ?? "localhost",
|
||||||
|
port: parseInt(process.env.REDIS_PORT ?? "6379"),
|
||||||
|
password: process.env.REDIS_PASSWORD ?? null,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
function getRedisConfiguration(): {
|
||||||
|
port: number;
|
||||||
|
host: string;
|
||||||
|
password: string | null;
|
||||||
|
} {
|
||||||
|
return configuration.redis;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createRedisInstance(config = getRedisConfiguration()) {
|
||||||
|
try {
|
||||||
|
const options: RedisOptions = {
|
||||||
|
host: config.host,
|
||||||
|
lazyConnect: true,
|
||||||
|
showFriendlyErrorStack: true,
|
||||||
|
enableAutoPipelining: true,
|
||||||
|
maxRetriesPerRequest: 0,
|
||||||
|
retryStrategy: (times: number) => {
|
||||||
|
if (times > 3) {
|
||||||
|
throw new Error(`[Redis] Could not connect after ${times} attempts`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Math.min(times * 200, 1000);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (config.port) {
|
||||||
|
options.port = config.port;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.password) {
|
||||||
|
options.password = config.password;
|
||||||
|
}
|
||||||
|
|
||||||
|
const redis = new Redis(options);
|
||||||
|
|
||||||
|
redis.on("error", (error: unknown) => {
|
||||||
|
console.warn("[Redis] Error connecting", error);
|
||||||
|
});
|
||||||
|
|
||||||
|
return redis;
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error(`[Redis] Could not create a Redis instance`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,7 +3,13 @@ const nextConfig = {
|
||||||
reactStrictMode: true,
|
reactStrictMode: true,
|
||||||
swcMinify: true,
|
swcMinify: true,
|
||||||
images: {
|
images: {
|
||||||
domains: ["cdn.discordapp.com", "static-cdn.jtvnw.net", "cdn.7tv.app"],
|
domains: [
|
||||||
|
"cdn.discordapp.com",
|
||||||
|
"static-cdn.jtvnw.net",
|
||||||
|
"cdn.7tv.app",
|
||||||
|
"cdn.betterttv.net",
|
||||||
|
"cdn.frankerfacez.com",
|
||||||
|
],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
101
package-lock.json
generated
101
package-lock.json
generated
|
@ -11,7 +11,7 @@
|
||||||
"eslint": "8.28.0",
|
"eslint": "8.28.0",
|
||||||
"eslint-config-next": "13.0.4",
|
"eslint-config-next": "13.0.4",
|
||||||
"framer-motion": "^7.6.19",
|
"framer-motion": "^7.6.19",
|
||||||
"ioredis": "^4.28.5",
|
"ioredis": "^5.2.5",
|
||||||
"next": "13.0.4",
|
"next": "13.0.4",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
|
@ -122,6 +122,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
|
||||||
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA=="
|
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@ioredis/commands": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg=="
|
||||||
|
},
|
||||||
"node_modules/@motionone/animation": {
|
"node_modules/@motionone/animation": {
|
||||||
"version": "10.15.1",
|
"version": "10.15.1",
|
||||||
"resolved": "https://registry.npmjs.org/@motionone/animation/-/animation-10.15.1.tgz",
|
"resolved": "https://registry.npmjs.org/@motionone/animation/-/animation-10.15.1.tgz",
|
||||||
|
@ -1342,9 +1347,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/denque": {
|
"node_modules/denque": {
|
||||||
"version": "1.5.1",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
|
||||||
"integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw==",
|
"integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10"
|
"node": ">=0.10"
|
||||||
}
|
}
|
||||||
|
@ -2515,38 +2520,28 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ioredis": {
|
"node_modules/ioredis": {
|
||||||
"version": "4.28.5",
|
"version": "5.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-4.28.5.tgz",
|
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.2.5.tgz",
|
||||||
"integrity": "sha512-3GYo0GJtLqgNXj4YhrisLaNNvWSNwSS2wS4OELGfGxH8I69+XfNdnmV1AyN+ZqMh0i7eX+SWjrwFKDBDgfBC1A==",
|
"integrity": "sha512-7HKo/ClM2DGLRXdFq8ruS3Uuadensz4A76wPOU0adqlOqd1qkhoLPDaBhmVhUhNGpB+J65/bhLmNB8DDY99HJQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@ioredis/commands": "^1.1.1",
|
||||||
"cluster-key-slot": "^1.1.0",
|
"cluster-key-slot": "^1.1.0",
|
||||||
"debug": "^4.3.1",
|
"debug": "^4.3.4",
|
||||||
"denque": "^1.1.0",
|
"denque": "^2.0.1",
|
||||||
"lodash.defaults": "^4.2.0",
|
"lodash.defaults": "^4.2.0",
|
||||||
"lodash.flatten": "^4.4.0",
|
|
||||||
"lodash.isarguments": "^3.1.0",
|
"lodash.isarguments": "^3.1.0",
|
||||||
"p-map": "^2.1.0",
|
|
||||||
"redis-commands": "1.7.0",
|
|
||||||
"redis-errors": "^1.2.0",
|
"redis-errors": "^1.2.0",
|
||||||
"redis-parser": "^3.0.0",
|
"redis-parser": "^3.0.0",
|
||||||
"standard-as-callback": "^2.1.0"
|
"standard-as-callback": "^2.1.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=12.22.0"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
"url": "https://opencollective.com/ioredis"
|
"url": "https://opencollective.com/ioredis"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ioredis/node_modules/p-map": {
|
|
||||||
"version": "2.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz",
|
|
||||||
"integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/is-arrayish": {
|
"node_modules/is-arrayish": {
|
||||||
"version": "0.3.2",
|
"version": "0.3.2",
|
||||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
|
||||||
|
@ -2841,9 +2836,9 @@
|
||||||
"integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="
|
"integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="
|
||||||
},
|
},
|
||||||
"node_modules/json5": {
|
"node_modules/json5": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
|
||||||
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
|
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"minimist": "^1.2.0"
|
"minimist": "^1.2.0"
|
||||||
},
|
},
|
||||||
|
@ -3050,11 +3045,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
|
||||||
"integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ=="
|
"integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ=="
|
||||||
},
|
},
|
||||||
"node_modules/lodash.flatten": {
|
|
||||||
"version": "4.4.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
|
|
||||||
"integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g=="
|
|
||||||
},
|
|
||||||
"node_modules/lodash.isarguments": {
|
"node_modules/lodash.isarguments": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
|
||||||
|
@ -4025,11 +4015,6 @@
|
||||||
"node": ">=8.10.0"
|
"node": ">=8.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/redis-commands": {
|
|
||||||
"version": "1.7.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.7.0.tgz",
|
|
||||||
"integrity": "sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ=="
|
|
||||||
},
|
|
||||||
"node_modules/redis-errors": {
|
"node_modules/redis-errors": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
|
||||||
|
@ -5075,6 +5060,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz",
|
||||||
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA=="
|
"integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA=="
|
||||||
},
|
},
|
||||||
|
"@ioredis/commands": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@ioredis/commands/-/commands-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg=="
|
||||||
|
},
|
||||||
"@motionone/animation": {
|
"@motionone/animation": {
|
||||||
"version": "10.15.1",
|
"version": "10.15.1",
|
||||||
"resolved": "https://registry.npmjs.org/@motionone/animation/-/animation-10.15.1.tgz",
|
"resolved": "https://registry.npmjs.org/@motionone/animation/-/animation-10.15.1.tgz",
|
||||||
|
@ -5868,9 +5858,9 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"denque": {
|
"denque": {
|
||||||
"version": "1.5.1",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz",
|
||||||
"integrity": "sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw=="
|
"integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw=="
|
||||||
},
|
},
|
||||||
"detect-libc": {
|
"detect-libc": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
|
@ -6728,28 +6718,19 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ioredis": {
|
"ioredis": {
|
||||||
"version": "4.28.5",
|
"version": "5.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-4.28.5.tgz",
|
"resolved": "https://registry.npmjs.org/ioredis/-/ioredis-5.2.5.tgz",
|
||||||
"integrity": "sha512-3GYo0GJtLqgNXj4YhrisLaNNvWSNwSS2wS4OELGfGxH8I69+XfNdnmV1AyN+ZqMh0i7eX+SWjrwFKDBDgfBC1A==",
|
"integrity": "sha512-7HKo/ClM2DGLRXdFq8ruS3Uuadensz4A76wPOU0adqlOqd1qkhoLPDaBhmVhUhNGpB+J65/bhLmNB8DDY99HJQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
|
"@ioredis/commands": "^1.1.1",
|
||||||
"cluster-key-slot": "^1.1.0",
|
"cluster-key-slot": "^1.1.0",
|
||||||
"debug": "^4.3.1",
|
"debug": "^4.3.4",
|
||||||
"denque": "^1.1.0",
|
"denque": "^2.0.1",
|
||||||
"lodash.defaults": "^4.2.0",
|
"lodash.defaults": "^4.2.0",
|
||||||
"lodash.flatten": "^4.4.0",
|
|
||||||
"lodash.isarguments": "^3.1.0",
|
"lodash.isarguments": "^3.1.0",
|
||||||
"p-map": "^2.1.0",
|
|
||||||
"redis-commands": "1.7.0",
|
|
||||||
"redis-errors": "^1.2.0",
|
"redis-errors": "^1.2.0",
|
||||||
"redis-parser": "^3.0.0",
|
"redis-parser": "^3.0.0",
|
||||||
"standard-as-callback": "^2.1.0"
|
"standard-as-callback": "^2.1.0"
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"p-map": {
|
|
||||||
"version": "2.1.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz",
|
|
||||||
"integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw=="
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"is-arrayish": {
|
"is-arrayish": {
|
||||||
|
@ -6940,9 +6921,9 @@
|
||||||
"integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="
|
"integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw=="
|
||||||
},
|
},
|
||||||
"json5": {
|
"json5": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
|
||||||
"integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
|
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"minimist": "^1.2.0"
|
"minimist": "^1.2.0"
|
||||||
}
|
}
|
||||||
|
@ -7094,11 +7075,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
|
||||||
"integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ=="
|
"integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ=="
|
||||||
},
|
},
|
||||||
"lodash.flatten": {
|
|
||||||
"version": "4.4.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
|
|
||||||
"integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g=="
|
|
||||||
},
|
|
||||||
"lodash.isarguments": {
|
"lodash.isarguments": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
|
||||||
|
@ -7736,11 +7712,6 @@
|
||||||
"picomatch": "^2.2.1"
|
"picomatch": "^2.2.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"redis-commands": {
|
|
||||||
"version": "1.7.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.7.0.tgz",
|
|
||||||
"integrity": "sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ=="
|
|
||||||
},
|
|
||||||
"redis-errors": {
|
"redis-errors": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
"eslint": "8.28.0",
|
"eslint": "8.28.0",
|
||||||
"eslint-config-next": "13.0.4",
|
"eslint-config-next": "13.0.4",
|
||||||
"framer-motion": "^7.6.19",
|
"framer-motion": "^7.6.19",
|
||||||
"ioredis": "^4.28.5",
|
"ioredis": "^5.2.5",
|
||||||
"next": "13.0.4",
|
"next": "13.0.4",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import type { NextApiRequest, NextApiResponse } from "next";
|
import type { NextApiRequest, NextApiResponse } from "next";
|
||||||
|
import { createRedisInstance } from "../../../misc/redis";
|
||||||
import { getChannelEmotes, getGlobalEmotes } from "../../../misc/7TVAPI";
|
import { getChannelEmotes, getGlobalEmotes } from "../../../misc/7TVAPI";
|
||||||
|
|
||||||
type Data = {
|
type Data = {
|
||||||
|
@ -9,10 +10,19 @@ export default async function handler(
|
||||||
req: NextApiRequest,
|
req: NextApiRequest,
|
||||||
res: NextApiResponse<Data>
|
res: NextApiResponse<Data>
|
||||||
) {
|
) {
|
||||||
const channel = req.query.c
|
const redis = createRedisInstance();
|
||||||
? await getChannelEmotes(req.query.c as string)
|
|
||||||
: undefined;
|
|
||||||
const global = await getGlobalEmotes();
|
|
||||||
|
|
||||||
res.status(200).json({ channel, global });
|
try {
|
||||||
|
const channel = req.query.c
|
||||||
|
? await getChannelEmotes(redis, req.query.c as string)
|
||||||
|
: undefined;
|
||||||
|
const global = await getGlobalEmotes(redis);
|
||||||
|
redis.quit();
|
||||||
|
res.status(200).json({ channel, global });
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
res
|
||||||
|
.status(500)
|
||||||
|
.json({ error: { message: "7TV or internal API is down", code: 10000 } });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
30
pages/api/bttv/emotes.ts
Normal file
30
pages/api/bttv/emotes.ts
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import type { NextApiRequest, NextApiResponse } from "next";
|
||||||
|
import { createRedisInstance } from "../../../misc/redis";
|
||||||
|
import { getUserByID, getGlobalEmotes } from "../../../misc/BTTVAPI";
|
||||||
|
|
||||||
|
type Data = {
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default async function handler(
|
||||||
|
req: NextApiRequest,
|
||||||
|
res: NextApiResponse<Data>
|
||||||
|
) {
|
||||||
|
const redis = createRedisInstance();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const channel = req.query.c
|
||||||
|
? (await getUserByID(redis, req.query.c as string)).channelEmotes
|
||||||
|
: undefined;
|
||||||
|
const global = await getGlobalEmotes(redis);
|
||||||
|
redis.quit();
|
||||||
|
res.status(200).json({ channel, global });
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
res
|
||||||
|
.status(500)
|
||||||
|
.json({
|
||||||
|
error: { message: "BTTV or internal API is down", code: 10200 },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
804
pages/api/fakePrices.ts
Normal file
804
pages/api/fakePrices.ts
Normal file
|
@ -0,0 +1,804 @@
|
||||||
|
import type { NextApiRequest, NextApiResponse } from "next";
|
||||||
|
|
||||||
|
type Data = {
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default async function handler(
|
||||||
|
req: NextApiRequest,
|
||||||
|
res: NextApiResponse<Data>
|
||||||
|
) {
|
||||||
|
const emote = req.query.emote ? (req.query.emote as string) : undefined;
|
||||||
|
if (!emote) {
|
||||||
|
res.status(200).json({ data: fakePrices });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
res.status(200).json({ data: fakePrices[emote] });
|
||||||
|
}
|
||||||
|
|
||||||
|
const fakePrices: { [key: string]: number } = {
|
||||||
|
"3Head": 521,
|
||||||
|
"4Health": 801,
|
||||||
|
":3": 104,
|
||||||
|
":(": 799,
|
||||||
|
AAAA: 717,
|
||||||
|
AAAAUUUUUUGHHHHHHH: 342,
|
||||||
|
AINTNAURWAY: 195,
|
||||||
|
AREYOUAFEMBOY: 135,
|
||||||
|
AREYOUAGIRL: 494,
|
||||||
|
AYAYAjam: 907,
|
||||||
|
Adge: 646,
|
||||||
|
AlienPls3: 460,
|
||||||
|
Amonge: 608,
|
||||||
|
AngelThump: 195,
|
||||||
|
AnnyLebronJam: 967,
|
||||||
|
Aware: 571,
|
||||||
|
BAND: 472,
|
||||||
|
BASED: 794,
|
||||||
|
BEGGING: 365,
|
||||||
|
BLUBBERS: 211,
|
||||||
|
BLUBBERSWTF: 713,
|
||||||
|
BOOBEST: 107,
|
||||||
|
BOTHA: 472,
|
||||||
|
BRUHgers: 536,
|
||||||
|
Baby: 927,
|
||||||
|
Binoculars: 441,
|
||||||
|
Blindge: 426,
|
||||||
|
BocchiPossessed: 545,
|
||||||
|
Bruhgi: 779,
|
||||||
|
CEASE: 708,
|
||||||
|
COCKA: 656,
|
||||||
|
CapybaraStare: 295,
|
||||||
|
CatChest: 267,
|
||||||
|
ChadMeeting: 454,
|
||||||
|
Chatting: 330,
|
||||||
|
ChugU: 661,
|
||||||
|
Clueless: 888,
|
||||||
|
Coldge: 314,
|
||||||
|
Comfi: 187,
|
||||||
|
Copege: 841,
|
||||||
|
Corpa: 536,
|
||||||
|
CumTime: 199,
|
||||||
|
DIESOFAYAYA: 657,
|
||||||
|
DIESOFCRINGE: 320,
|
||||||
|
DONUT: 57,
|
||||||
|
Danki: 864,
|
||||||
|
Deadge: 322,
|
||||||
|
Despairge: 437,
|
||||||
|
Deutschge: 626,
|
||||||
|
EDM: 572,
|
||||||
|
FLASHBANG: 308,
|
||||||
|
FeelsWeakMan: 88,
|
||||||
|
Fishinge: 956,
|
||||||
|
Flushed: 290,
|
||||||
|
FluteTime: 557,
|
||||||
|
GOODONE: 804,
|
||||||
|
GachiPls: 415,
|
||||||
|
Gambage: 876,
|
||||||
|
Gayge: 434,
|
||||||
|
GetOutOfMyHead: 338,
|
||||||
|
GoodGirl: 761,
|
||||||
|
GroupWankge: 540,
|
||||||
|
GuysRefreshChatterinoIUploadedAnotherEmote: 677,
|
||||||
|
HACKERMANS: 85,
|
||||||
|
HUH: 582,
|
||||||
|
HYPERS: 142,
|
||||||
|
Homi: 745,
|
||||||
|
HopOnBlueArchive: 386,
|
||||||
|
IDC: 277,
|
||||||
|
ILOST: 894,
|
||||||
|
JIGACHAD: 865,
|
||||||
|
Jamgie: 156,
|
||||||
|
Jammies: 308,
|
||||||
|
Joel: 586,
|
||||||
|
KEKW: 356,
|
||||||
|
KKool: 821,
|
||||||
|
KoroneOkite: 90,
|
||||||
|
LETHIMCOOK: 940,
|
||||||
|
LICKA: 866,
|
||||||
|
LUBBERS: 808,
|
||||||
|
LULE: 244,
|
||||||
|
Lagging: 314,
|
||||||
|
LickAnnyThighs: 66,
|
||||||
|
Life: 894,
|
||||||
|
LoveForever: 21,
|
||||||
|
MODS: 180,
|
||||||
|
MYHEART: 122,
|
||||||
|
MaN: 181,
|
||||||
|
MadgeJuice: 926,
|
||||||
|
MadgeTime: 481,
|
||||||
|
Madgeclap: 534,
|
||||||
|
Malding: 940,
|
||||||
|
Maxwell: 656,
|
||||||
|
MyHonestReaction: 314,
|
||||||
|
NAUR: 93,
|
||||||
|
NGOthis: 454,
|
||||||
|
NOBOOBS: 855,
|
||||||
|
NODDERS: 836,
|
||||||
|
NOTED: 293,
|
||||||
|
Naruga: 572,
|
||||||
|
Naruge: 872,
|
||||||
|
Nerdge: 46,
|
||||||
|
NessieTwerk: 666,
|
||||||
|
OFFLINECHAT: 780,
|
||||||
|
OMEGA: 934,
|
||||||
|
OMG: 631,
|
||||||
|
"OhTheMiseryEverybodyWantsToBeMyEnemySpareTheSympathyEverybodyWantsToBeMyEnemy-y-y-y-y": 798,
|
||||||
|
Okayeg: 485,
|
||||||
|
OkaygeBusiness: 493,
|
||||||
|
Oldge: 763,
|
||||||
|
OrangexddRun: 96,
|
||||||
|
PEPELEPSY: 122,
|
||||||
|
PLEASE: 607,
|
||||||
|
PagMan: 775,
|
||||||
|
PantsGrab: 503,
|
||||||
|
Party: 181,
|
||||||
|
PeepoKittyHug: 360,
|
||||||
|
PensiveWobble: 843,
|
||||||
|
PepeClown: 384,
|
||||||
|
PepeNPC: 131,
|
||||||
|
Pepepains: 105,
|
||||||
|
PepoG: 987,
|
||||||
|
PogOanny: 14,
|
||||||
|
PogTasty: 211,
|
||||||
|
PogU: 245,
|
||||||
|
Pogpega: 902,
|
||||||
|
PokiShare: 274,
|
||||||
|
Poorge: 789,
|
||||||
|
PoroRoast: 199,
|
||||||
|
Programming: 161,
|
||||||
|
RAGEY: 322,
|
||||||
|
RAVE: 67,
|
||||||
|
RESETTING: 749,
|
||||||
|
RIDING: 364,
|
||||||
|
RIPBOZO: 638,
|
||||||
|
Ratge: 981,
|
||||||
|
SCHIZO: 457,
|
||||||
|
SHITUP: 643,
|
||||||
|
SNIFFA: 220,
|
||||||
|
SPEED: 956,
|
||||||
|
SadCat: 747,
|
||||||
|
Sadeg: 313,
|
||||||
|
SadgeCry: 869,
|
||||||
|
SaguiPls: 363,
|
||||||
|
Siti: 396,
|
||||||
|
Smadge: 222,
|
||||||
|
SmugCat: 447,
|
||||||
|
SnowTime: 545,
|
||||||
|
SoCute: 317,
|
||||||
|
Spoopy: 281,
|
||||||
|
Suske: 642,
|
||||||
|
THESE: 401,
|
||||||
|
THIS: 311,
|
||||||
|
Tasty: 530,
|
||||||
|
ThisStream: 497,
|
||||||
|
TouchGrass: 608,
|
||||||
|
TurtleRush: 608,
|
||||||
|
UOHHH: 426,
|
||||||
|
VIBE: 939,
|
||||||
|
VIBEOFF: 36,
|
||||||
|
VaN: 479,
|
||||||
|
VeryBased: 456,
|
||||||
|
ViolinTime: 406,
|
||||||
|
WHAT: 941,
|
||||||
|
WHOMEGALUL: 804,
|
||||||
|
WakuWaku: 221,
|
||||||
|
WeebRun: 582,
|
||||||
|
WhoAsked: 459,
|
||||||
|
Wickedgi: 870,
|
||||||
|
Wigglecat: 649,
|
||||||
|
Wokege: 377,
|
||||||
|
YourMom: 939,
|
||||||
|
amongnnE: 142,
|
||||||
|
annE: 552,
|
||||||
|
annie: 292,
|
||||||
|
annyBlob: 471,
|
||||||
|
annyBop: 749,
|
||||||
|
annyCD: 673,
|
||||||
|
annyCucumber: 689,
|
||||||
|
annyDespair: 736,
|
||||||
|
annyExcitedHug: 926,
|
||||||
|
annyGAMBA: 885,
|
||||||
|
annyGasm: 49,
|
||||||
|
annyGlare: 462,
|
||||||
|
annyHappy: 960,
|
||||||
|
annyHug: 979,
|
||||||
|
annyJam: 544,
|
||||||
|
annyLava: 288,
|
||||||
|
annyNODDERS: 730,
|
||||||
|
annyNOW: 68,
|
||||||
|
annyOffline: 241,
|
||||||
|
annyPadoru: 453,
|
||||||
|
annyPag: 377,
|
||||||
|
annyPoggies: 729,
|
||||||
|
annyPooPoo: 295,
|
||||||
|
annySCHIZO: 766,
|
||||||
|
annySmile: 467,
|
||||||
|
annySussy: 695,
|
||||||
|
annySwipe: 992,
|
||||||
|
annyTalk: 951,
|
||||||
|
annyThighs: 458,
|
||||||
|
annyVibe: 914,
|
||||||
|
annykiss: 308,
|
||||||
|
annysilly: 996,
|
||||||
|
annystare: 34,
|
||||||
|
annytfCum: 27,
|
||||||
|
anyaPls: 322,
|
||||||
|
anyatf: 58,
|
||||||
|
baseg: 551,
|
||||||
|
borpaSpin: 793,
|
||||||
|
burh: 716,
|
||||||
|
catKISS: 88,
|
||||||
|
catRAVE: 912,
|
||||||
|
catbaby: 673,
|
||||||
|
chatlookwhatannytaughtme: 515,
|
||||||
|
danse: 213,
|
||||||
|
deadass: 815,
|
||||||
|
degen: 551,
|
||||||
|
dejj: 843,
|
||||||
|
donowall: 660,
|
||||||
|
dvaAss: 871,
|
||||||
|
elmoFire: 117,
|
||||||
|
ewLeague: 240,
|
||||||
|
ewOverwatch: 397,
|
||||||
|
forsen: 482,
|
||||||
|
forsenGa: 327,
|
||||||
|
forsenGaPick: 149,
|
||||||
|
forsenLaughingAtYou: 292,
|
||||||
|
frenn: 575,
|
||||||
|
golive: 103,
|
||||||
|
guraFukkireta: 767,
|
||||||
|
guraWiggle: 132,
|
||||||
|
guraWink: 891,
|
||||||
|
happ: 525,
|
||||||
|
heCrazy: 437,
|
||||||
|
hiThere: 54,
|
||||||
|
hmmMeeting: 749,
|
||||||
|
iAsked: 203,
|
||||||
|
jupijej: 207,
|
||||||
|
kiss0: 738,
|
||||||
|
kok: 313,
|
||||||
|
koklick: 990,
|
||||||
|
koroneWink: 824,
|
||||||
|
lebronJAM: 890,
|
||||||
|
liccanny: 205,
|
||||||
|
lobaPls: 436,
|
||||||
|
majj: 813,
|
||||||
|
meow: 757,
|
||||||
|
monkaE: 376,
|
||||||
|
monkaLaugh: 335,
|
||||||
|
nekoNya: 948,
|
||||||
|
nessieWalk: 672,
|
||||||
|
nise: 658,
|
||||||
|
nyanPls: 330,
|
||||||
|
pL: 38,
|
||||||
|
paapoHappy: 126,
|
||||||
|
peepoCat: 673,
|
||||||
|
peepoClap: 772,
|
||||||
|
peepoFAT: 408,
|
||||||
|
peepoFeet: 909,
|
||||||
|
peepoFinger: 185,
|
||||||
|
peepoFlower: 569,
|
||||||
|
peepoFlute: 361,
|
||||||
|
peepoHeadbang: 615,
|
||||||
|
peepoHigh: 125,
|
||||||
|
peepoLeaveToAnny: 711,
|
||||||
|
peepoPag: 101,
|
||||||
|
peepoPopcorn: 234,
|
||||||
|
peepoRant: 628,
|
||||||
|
peepoRiot: 874,
|
||||||
|
peepoSnow: 90,
|
||||||
|
peepoStuck: 188,
|
||||||
|
peepoTalk: 452,
|
||||||
|
pepeKneel: 87,
|
||||||
|
pepePoint: 641,
|
||||||
|
pepegaJAMMER: 603,
|
||||||
|
plink: 892,
|
||||||
|
poggcrazy: 319,
|
||||||
|
pogs: 829,
|
||||||
|
poroPls: 87,
|
||||||
|
ppHop: 589,
|
||||||
|
ppHopper: 843,
|
||||||
|
ppPoof: 188,
|
||||||
|
sadWankge: 300,
|
||||||
|
sajj: 44,
|
||||||
|
sitt: 450,
|
||||||
|
soncic: 483,
|
||||||
|
sonic: 464,
|
||||||
|
squirrelJAM: 431,
|
||||||
|
toffee1: 591,
|
||||||
|
toffee2: 51,
|
||||||
|
toffee3: 3,
|
||||||
|
toffeeBlankies: 249,
|
||||||
|
toffeeBop: 801,
|
||||||
|
toffeeChat: 405,
|
||||||
|
toffeeClap: 552,
|
||||||
|
toffeeComfy: 383,
|
||||||
|
toffeeConfused: 548,
|
||||||
|
toffeeDinkDonk: 782,
|
||||||
|
toffeePat: 235,
|
||||||
|
toffeeTap: 815,
|
||||||
|
vp: 113,
|
||||||
|
wideVIBE: 972,
|
||||||
|
wideannyBop: 866,
|
||||||
|
widepeepoHappy: 969,
|
||||||
|
widepeepoMASTURBATION77769420GANGSHITNOMOREFORTNITE19DOLLERFORTNITECARD: 846,
|
||||||
|
xQchatting: 196,
|
||||||
|
xdd666: 700,
|
||||||
|
xddfdhjsd0f76ds5r26FDSFHD88hjdbsa67vr7xlLLhdsgfcxz632nkDFSGATVMVLN8CXFJJMVMMMM111111111111111111111: 866,
|
||||||
|
xdding: 735,
|
||||||
|
xqcCoomer: 397,
|
||||||
|
xqcGoofy: 360,
|
||||||
|
xqcRecord: 773,
|
||||||
|
xqcTwerk: 531,
|
||||||
|
yayAnny: 437,
|
||||||
|
yoshiJAM: 137,
|
||||||
|
zSpooky: 350,
|
||||||
|
zyzzBass: 680,
|
||||||
|
// bttv
|
||||||
|
":tf:": 325,
|
||||||
|
CiGrip: 697,
|
||||||
|
DatSauce: 903,
|
||||||
|
ForeverAlone: 663,
|
||||||
|
GabeN: 497,
|
||||||
|
HailHelix: 447,
|
||||||
|
ShoopDaWhoop: 502,
|
||||||
|
"M&Mjc": 196,
|
||||||
|
bttvNice: 558,
|
||||||
|
TwaT: 176,
|
||||||
|
WatChuSay: 947,
|
||||||
|
tehPoleCat: 611,
|
||||||
|
TaxiBro: 527,
|
||||||
|
BroBalt: 384,
|
||||||
|
CandianRage: 431,
|
||||||
|
"D:": 192,
|
||||||
|
VisLaud: 966,
|
||||||
|
KaRappa: 247,
|
||||||
|
FishMoley: 276,
|
||||||
|
Hhhehehe: 945,
|
||||||
|
KKona: 596,
|
||||||
|
PoleDoge: 485,
|
||||||
|
sosGame: 473,
|
||||||
|
CruW: 591,
|
||||||
|
RarePepe: 866,
|
||||||
|
haHAA: 979,
|
||||||
|
FeelsBirthdayMan: 536,
|
||||||
|
RonSmug: 776,
|
||||||
|
KappaCool: 777,
|
||||||
|
FeelsBadMan: 483,
|
||||||
|
bUrself: 934,
|
||||||
|
ConcernDoge: 520,
|
||||||
|
FeelsGoodMan: 202,
|
||||||
|
FireSpeed: 82,
|
||||||
|
NaM: 412,
|
||||||
|
SourPls: 231,
|
||||||
|
FeelsSnowMan: 639,
|
||||||
|
FeelsSnowyMan: 929,
|
||||||
|
LuL: 603,
|
||||||
|
SoSnowy: 647,
|
||||||
|
SaltyCorn: 486,
|
||||||
|
monkaS: 189,
|
||||||
|
VapeNation: 570,
|
||||||
|
ariW: 926,
|
||||||
|
notsquishY: 438,
|
||||||
|
FeelsAmazingMan: 92,
|
||||||
|
DuckerZ: 417,
|
||||||
|
IceCold: 21,
|
||||||
|
SqShy: 84,
|
||||||
|
Wowee: 533,
|
||||||
|
WubTF: 494,
|
||||||
|
cvR: 913,
|
||||||
|
cvL: 337,
|
||||||
|
cvHazmat: 599,
|
||||||
|
cvMask: 423,
|
||||||
|
DogChamp: 947,
|
||||||
|
annytfBanana: 730,
|
||||||
|
annySaur: 236,
|
||||||
|
annytfBlink: 108,
|
||||||
|
AnnySilly: 469,
|
||||||
|
annyBlankies: 747,
|
||||||
|
annyHop: 861,
|
||||||
|
annyHopper: 941,
|
||||||
|
annyTeaTime: 398,
|
||||||
|
annyD: 530,
|
||||||
|
annyDVibe: 907,
|
||||||
|
annyDHyper: 451,
|
||||||
|
annyDFast: 117,
|
||||||
|
KissaVei: 158,
|
||||||
|
Annie: 597,
|
||||||
|
annyPls: 91,
|
||||||
|
// ffz
|
||||||
|
monkaW: 969,
|
||||||
|
"5Head": 750,
|
||||||
|
Prayge: 434,
|
||||||
|
PauseChamp: 903,
|
||||||
|
Pepega: 817,
|
||||||
|
TWINGO: 256,
|
||||||
|
PepeHands: 190,
|
||||||
|
monkaTOS: 146,
|
||||||
|
monkaHmm: 549,
|
||||||
|
Dolan: 536,
|
||||||
|
SmileW: 166,
|
||||||
|
ABABABABA: 95,
|
||||||
|
peepoBlanket: 798,
|
||||||
|
pikachuS: 715,
|
||||||
|
AYAYAHyper: 164,
|
||||||
|
YEP: 371,
|
||||||
|
widepeepoBlanket: 100,
|
||||||
|
HandsUp: 684,
|
||||||
|
peepoSad: 167,
|
||||||
|
HyperKorone: 456,
|
||||||
|
AYAYA: 503,
|
||||||
|
forsenCD: 344,
|
||||||
|
Hahaa: 291,
|
||||||
|
LULW: 463,
|
||||||
|
WICKED: 133,
|
||||||
|
EZY: 494,
|
||||||
|
OkayChamp: 950,
|
||||||
|
PepegaPig: 217,
|
||||||
|
POGGIES: 487,
|
||||||
|
peepoWTF: 734,
|
||||||
|
ConfusedCat: 508,
|
||||||
|
PainPeko: 433,
|
||||||
|
KKrikey: 235,
|
||||||
|
COPIUM: 582,
|
||||||
|
Madge: 595,
|
||||||
|
Catge: 811,
|
||||||
|
stopbeingMean: 522,
|
||||||
|
NOPE: 262,
|
||||||
|
OMEGALUL: 648,
|
||||||
|
AYAYAY: 725,
|
||||||
|
PogO: 548,
|
||||||
|
Sadge: 41,
|
||||||
|
PepegaPhone: 800,
|
||||||
|
Widega: 543,
|
||||||
|
ZrehplaR: 23,
|
||||||
|
YooHoo: 617,
|
||||||
|
ManChicken: 588,
|
||||||
|
BeanieHipster: 480,
|
||||||
|
CatBag: 253,
|
||||||
|
ZreknarF: 143,
|
||||||
|
LilZ: 952,
|
||||||
|
ZliL: 662,
|
||||||
|
LaterSooner: 375,
|
||||||
|
BORT: 738,
|
||||||
|
OBOY: 942,
|
||||||
|
OiMinna: 354,
|
||||||
|
AndKnuckles: 828,
|
||||||
|
// twitch
|
||||||
|
annytfRaid: 493,
|
||||||
|
annytfNote: 893,
|
||||||
|
annytfPout: 971,
|
||||||
|
annytfAyaya: 180,
|
||||||
|
annytfPika: 328,
|
||||||
|
annytfPrime: 830,
|
||||||
|
annytfLewd: 314,
|
||||||
|
annytfRave: 615,
|
||||||
|
annytfLurk: 898,
|
||||||
|
annytfPog: 958,
|
||||||
|
annytfD: 759,
|
||||||
|
annytfCry: 399,
|
||||||
|
annytfHeart: 472,
|
||||||
|
annytfSad: 390,
|
||||||
|
annytfMelt: 157,
|
||||||
|
annytfWICKED: 94,
|
||||||
|
annytfCheer: 780,
|
||||||
|
annytfREEE: 272,
|
||||||
|
annytfLUL: 122,
|
||||||
|
annytfScuffed: 318,
|
||||||
|
annytfAngy: 677,
|
||||||
|
annytfHug: 826,
|
||||||
|
annytfCool: 121,
|
||||||
|
annytfPain: 16,
|
||||||
|
annytfBonk: 949,
|
||||||
|
annytfKnuckles: 182,
|
||||||
|
annytfSigh: 220,
|
||||||
|
annytfWoah: 582,
|
||||||
|
annytfBite: 580,
|
||||||
|
annytfSilly: 837,
|
||||||
|
annytfWow: 381,
|
||||||
|
annytfPray: 438,
|
||||||
|
annytfPats: 410,
|
||||||
|
annytfGasm: 822,
|
||||||
|
annytfSit: 39,
|
||||||
|
annytfFlower: 137,
|
||||||
|
annytfLeave: 819,
|
||||||
|
annytfGamba: 847,
|
||||||
|
annytfLuv: 483,
|
||||||
|
annytfHarucchiHug: 142,
|
||||||
|
annytfAnnE: 324,
|
||||||
|
annytfDinkDonk: 380,
|
||||||
|
annytfAhriluv: 232,
|
||||||
|
annytfW: 101,
|
||||||
|
annytfWoke: 145,
|
||||||
|
annytfBedge: 409,
|
||||||
|
annytfBusiness: 142,
|
||||||
|
annytfPeek: 98,
|
||||||
|
annytfDonowall: 581,
|
||||||
|
NewRecord: 836,
|
||||||
|
Awwdible: 794,
|
||||||
|
Lechonk: 567,
|
||||||
|
Getcamped: 378,
|
||||||
|
SUBprise: 580,
|
||||||
|
FallHalp: 95,
|
||||||
|
FallCry: 450,
|
||||||
|
FallWinning: 261,
|
||||||
|
MechaRobot: 984,
|
||||||
|
ImTyping: 993,
|
||||||
|
Shush: 506,
|
||||||
|
MyAvatar: 41,
|
||||||
|
PizzaTime: 330,
|
||||||
|
LaundryBasket: 852,
|
||||||
|
ModLove: 683,
|
||||||
|
PotFriend: 605,
|
||||||
|
Jebasted: 72,
|
||||||
|
PogBones: 761,
|
||||||
|
PoroSad: 357,
|
||||||
|
KEKHeim: 290,
|
||||||
|
CaitlynS: 874,
|
||||||
|
HarleyWink: 244,
|
||||||
|
WhySoSerious: 705,
|
||||||
|
DarkKnight: 101,
|
||||||
|
FamilyMan: 278,
|
||||||
|
RyuChamp: 814,
|
||||||
|
HungryPaimon: 920,
|
||||||
|
TransgenderPride: 409,
|
||||||
|
PansexualPride: 707,
|
||||||
|
NonbinaryPride: 866,
|
||||||
|
LesbianPride: 763,
|
||||||
|
IntersexPride: 136,
|
||||||
|
GenderFluidPride: 73,
|
||||||
|
GayPride: 471,
|
||||||
|
BisexualPride: 163,
|
||||||
|
AsexualPride: 533,
|
||||||
|
PogChamp: 898,
|
||||||
|
GlitchNRG: 877,
|
||||||
|
GlitchLit: 45,
|
||||||
|
StinkyGlitch: 697,
|
||||||
|
GlitchCat: 208,
|
||||||
|
FootGoal: 542,
|
||||||
|
FootYellow: 297,
|
||||||
|
FootBall: 679,
|
||||||
|
BlackLivesMatter: 637,
|
||||||
|
ExtraLife: 394,
|
||||||
|
VirtualHug: 452,
|
||||||
|
"R-)": 779,
|
||||||
|
"R)": 242,
|
||||||
|
";-p": 911,
|
||||||
|
";p": 168,
|
||||||
|
";-P": 584,
|
||||||
|
";P": 571,
|
||||||
|
":-p": 758,
|
||||||
|
":p": 709,
|
||||||
|
":-P": 137,
|
||||||
|
":P": 602,
|
||||||
|
";-)": 349,
|
||||||
|
";)": 745,
|
||||||
|
":-\\": 30,
|
||||||
|
":\\": 725,
|
||||||
|
":-/": 403,
|
||||||
|
":/": 187,
|
||||||
|
"<3": 51,
|
||||||
|
":-o": 622,
|
||||||
|
":o": 384,
|
||||||
|
":-O": 994,
|
||||||
|
":O": 629,
|
||||||
|
"8-)": 881,
|
||||||
|
"B-)": 390,
|
||||||
|
"B)": 489,
|
||||||
|
"o.o": 570,
|
||||||
|
o_o: 738,
|
||||||
|
"o.O": 287,
|
||||||
|
o_O: 168,
|
||||||
|
"O.O": 452,
|
||||||
|
O_O: 33,
|
||||||
|
"O.o": 187,
|
||||||
|
O_o: 513,
|
||||||
|
":-Z": 729,
|
||||||
|
":Z": 762,
|
||||||
|
":-z": 658,
|
||||||
|
":z": 526,
|
||||||
|
":-|": 978,
|
||||||
|
":|": 224,
|
||||||
|
">(": 141,
|
||||||
|
":-D": 699,
|
||||||
|
":D": 926,
|
||||||
|
":-(": 864,
|
||||||
|
":-)": 141,
|
||||||
|
BOP: 826,
|
||||||
|
SingsNote: 46,
|
||||||
|
SingsMic: 347,
|
||||||
|
TwitchSings: 419,
|
||||||
|
SoonerLater: 187,
|
||||||
|
HolidayTree: 822,
|
||||||
|
HolidaySanta: 340,
|
||||||
|
HolidayPresent: 830,
|
||||||
|
HolidayLog: 251,
|
||||||
|
HolidayCookie: 105,
|
||||||
|
GunRun: 899,
|
||||||
|
PixelBob: 829,
|
||||||
|
FBPenalty: 123,
|
||||||
|
FBChallenge: 645,
|
||||||
|
FBCatch: 769,
|
||||||
|
FBBlock: 284,
|
||||||
|
FBSpiral: 633,
|
||||||
|
FBPass: 365,
|
||||||
|
FBRun: 688,
|
||||||
|
MaxLOL: 17,
|
||||||
|
TwitchRPG: 258,
|
||||||
|
PinkMercy: 369,
|
||||||
|
MercyWing2: 2,
|
||||||
|
MercyWing1: 546,
|
||||||
|
PartyHat: 581,
|
||||||
|
EarthDay: 649,
|
||||||
|
TombRaid: 904,
|
||||||
|
PopCorn: 485,
|
||||||
|
FBtouchdown: 621,
|
||||||
|
TPFufun: 321,
|
||||||
|
TwitchVotes: 858,
|
||||||
|
DarkMode: 90,
|
||||||
|
HSWP: 729,
|
||||||
|
HSCheers: 802,
|
||||||
|
PowerUpL: 88,
|
||||||
|
PowerUpR: 616,
|
||||||
|
LUL: 958,
|
||||||
|
EntropyWins: 639,
|
||||||
|
TPcrunchyroll: 286,
|
||||||
|
TwitchUnity: 349,
|
||||||
|
Squid4: 548,
|
||||||
|
Squid3: 113,
|
||||||
|
Squid2: 768,
|
||||||
|
Squid1: 649,
|
||||||
|
CrreamAwk: 186,
|
||||||
|
CarlSmile: 822,
|
||||||
|
TwitchLit: 125,
|
||||||
|
TehePelo: 124,
|
||||||
|
TearGlove: 354,
|
||||||
|
SabaPing: 94,
|
||||||
|
PunOko: 145,
|
||||||
|
KonCha: 656,
|
||||||
|
Kappu: 597,
|
||||||
|
InuyoFace: 434,
|
||||||
|
BigPhish: 169,
|
||||||
|
BegWan: 621,
|
||||||
|
ThankEgg: 391,
|
||||||
|
MorphinTime: 106,
|
||||||
|
TheIlluminati: 531,
|
||||||
|
TBAngel: 925,
|
||||||
|
MVGame: 873,
|
||||||
|
NinjaGrumpy: 345,
|
||||||
|
PartyTime: 773,
|
||||||
|
RlyTho: 830,
|
||||||
|
UWot: 265,
|
||||||
|
YouDontSay: 744,
|
||||||
|
KAPOW: 757,
|
||||||
|
ItsBoshyTime: 605,
|
||||||
|
CoolStoryBob: 193,
|
||||||
|
TriHard: 121,
|
||||||
|
SuperVinlin: 500,
|
||||||
|
FreakinStinkin: 860,
|
||||||
|
Poooound: 411,
|
||||||
|
CurseLit: 318,
|
||||||
|
BatChest: 642,
|
||||||
|
BrainSlug: 48,
|
||||||
|
PrimeMe: 619,
|
||||||
|
StrawBeary: 813,
|
||||||
|
RaccAttack: 172,
|
||||||
|
UncleNox: 583,
|
||||||
|
WTRuck: 118,
|
||||||
|
TooSpicy: 761,
|
||||||
|
Jebaited: 363,
|
||||||
|
DogFace: 911,
|
||||||
|
BlargNaut: 148,
|
||||||
|
TakeNRG: 27,
|
||||||
|
GivePLZ: 581,
|
||||||
|
imGlitch: 514,
|
||||||
|
pastaThat: 48,
|
||||||
|
copyThis: 426,
|
||||||
|
UnSane: 97,
|
||||||
|
DatSheffy: 289,
|
||||||
|
TheTarFu: 818,
|
||||||
|
PicoMause: 570,
|
||||||
|
TinyFace: 31,
|
||||||
|
DxCat: 538,
|
||||||
|
RuleFive: 903,
|
||||||
|
VoteNay: 113,
|
||||||
|
VoteYea: 223,
|
||||||
|
PJSugar: 11,
|
||||||
|
DoritosChip: 187,
|
||||||
|
OpieOP: 977,
|
||||||
|
FutureMan: 893,
|
||||||
|
ChefFrank: 481,
|
||||||
|
StinkyCheese: 419,
|
||||||
|
NomNom: 162,
|
||||||
|
SmoocherZ: 863,
|
||||||
|
cmonBruh: 93,
|
||||||
|
KappaWealth: 776,
|
||||||
|
MikeHogu: 497,
|
||||||
|
VoHiYo: 646,
|
||||||
|
KomodoHype: 295,
|
||||||
|
SeriousSloth: 379,
|
||||||
|
OSFrog: 807,
|
||||||
|
OhMyDog: 124,
|
||||||
|
KappaClaus: 209,
|
||||||
|
KappaRoss: 298,
|
||||||
|
MingLee: 338,
|
||||||
|
SeemsGood: 89,
|
||||||
|
twitchRaid: 258,
|
||||||
|
bleedPurple: 949,
|
||||||
|
duDudu: 442,
|
||||||
|
riPepperonis: 192,
|
||||||
|
NotLikeThis: 838,
|
||||||
|
DendiFace: 534,
|
||||||
|
CoolCat: 995,
|
||||||
|
KappaPride: 915,
|
||||||
|
ShadyLulu: 372,
|
||||||
|
ArgieB8: 267,
|
||||||
|
CorgiDerp: 511,
|
||||||
|
PraiseIt: 557,
|
||||||
|
TTours: 122,
|
||||||
|
mcaT: 154,
|
||||||
|
NotATK: 388,
|
||||||
|
HeyGuys: 453,
|
||||||
|
Mau5: 421,
|
||||||
|
PRChase: 443,
|
||||||
|
WutFace: 20,
|
||||||
|
BuddhaBar: 622,
|
||||||
|
PermaSmug: 769,
|
||||||
|
panicBasket: 285,
|
||||||
|
BabyRage: 315,
|
||||||
|
HassaanChop: 246,
|
||||||
|
TheThing: 890,
|
||||||
|
EleGiggle: 284,
|
||||||
|
RitzMitz: 671,
|
||||||
|
YouWHY: 796,
|
||||||
|
PipeHype: 343,
|
||||||
|
BrokeBack: 440,
|
||||||
|
ANELE: 156,
|
||||||
|
PanicVis: 865,
|
||||||
|
GrammarKing: 77,
|
||||||
|
PeoplesChamp: 634,
|
||||||
|
SoBayed: 700,
|
||||||
|
BigBrother: 657,
|
||||||
|
Keepo: 800,
|
||||||
|
Kippa: 835,
|
||||||
|
RalpherZ: 322,
|
||||||
|
TF2John: 862,
|
||||||
|
ThunBeast: 408,
|
||||||
|
WholeWheat: 193,
|
||||||
|
DAESuppy: 787,
|
||||||
|
FailFish: 395,
|
||||||
|
HotPokket: 399,
|
||||||
|
ResidentSleeper: 460,
|
||||||
|
FUNgineer: 747,
|
||||||
|
PMSTwin: 830,
|
||||||
|
ShazBotstix: 315,
|
||||||
|
BibleThump: 278,
|
||||||
|
AsianGlow: 461,
|
||||||
|
DBstyle: 968,
|
||||||
|
BloodTrail: 687,
|
||||||
|
OneHand: 801,
|
||||||
|
FrankerZ: 893,
|
||||||
|
SMOrc: 727,
|
||||||
|
ArsonNoSexy: 99,
|
||||||
|
PunchTrees: 762,
|
||||||
|
SSSsss: 800,
|
||||||
|
Kreygasm: 413,
|
||||||
|
KevinTurtle: 111,
|
||||||
|
PJSalt: 115,
|
||||||
|
SwiftRage: 251,
|
||||||
|
DansGame: 46,
|
||||||
|
GingerPower: 762,
|
||||||
|
BCWarrior: 409,
|
||||||
|
MrDestructoid: 811,
|
||||||
|
JonCarnage: 359,
|
||||||
|
Kappa: 40,
|
||||||
|
RedCoat: 789,
|
||||||
|
TheRinger: 669,
|
||||||
|
StoneLightning: 867,
|
||||||
|
OptimizePrime: 654,
|
||||||
|
JKanStyle: 655,
|
||||||
|
":)": 594,
|
||||||
|
};
|
||||||
|
|
||||||
|
export { fakePrices };
|
|
@ -1,216 +0,0 @@
|
||||||
import type { NextApiRequest, NextApiResponse } from "next";
|
|
||||||
|
|
||||||
type Data = {
|
|
||||||
[key: string]: any;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default async function handler(
|
|
||||||
req: NextApiRequest,
|
|
||||||
res: NextApiResponse<Data>
|
|
||||||
) {
|
|
||||||
const sortBy = req.query.s ? (req.query.s as string) : undefined;
|
|
||||||
const sortAsc = req.query.a ? (req.query.a as string) : undefined;
|
|
||||||
|
|
||||||
let data = fakeData;
|
|
||||||
if (sortBy) {
|
|
||||||
if (sortBy === "netWorth") {
|
|
||||||
data = data.sort((a, b) => b.netWorth - a.netWorth);
|
|
||||||
} else if (sortBy === "dailyChange") {
|
|
||||||
data = data.sort((a, b) => b.dailyChange - a.dailyChange);
|
|
||||||
} else if (sortBy === "dailyChangePercent") {
|
|
||||||
data = data.sort((a, b) => b.dailyChangePercent - a.dailyChangePercent);
|
|
||||||
} else if (sortBy === "shares") {
|
|
||||||
data = data.sort((a, b) => b.shares - a.shares);
|
|
||||||
} else if (sortBy === "points") {
|
|
||||||
data = data.sort((a, b) => b.points - a.points);
|
|
||||||
} else if (sortBy === "name") {
|
|
||||||
data = data.sort((a, b) => a.name.localeCompare(b.name));
|
|
||||||
}
|
|
||||||
if (sortAsc === "true") {
|
|
||||||
// slow but only needed for temporary fake data anyway
|
|
||||||
data = data.reverse();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// fake loading time
|
|
||||||
await new Promise((resolve) =>
|
|
||||||
setTimeout(resolve, 250 + Math.random() * 1000)
|
|
||||||
);
|
|
||||||
res.status(200).json({ data });
|
|
||||||
}
|
|
||||||
|
|
||||||
interface fakeDataEntry {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
netWorth: number;
|
|
||||||
points: number;
|
|
||||||
shares: number;
|
|
||||||
dailyChange: number;
|
|
||||||
dailyChangePercent: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
const fakeData: fakeDataEntry[] = [
|
|
||||||
{
|
|
||||||
id: 4,
|
|
||||||
name: "3zachm",
|
|
||||||
netWorth: 10030, // stocks + points
|
|
||||||
points: 70, /// uninvested points
|
|
||||||
shares: 20,
|
|
||||||
dailyChange: -500,
|
|
||||||
dailyChangePercent: -0.0498504486540378863409770687936,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 1,
|
|
||||||
name: "ModulatingForce",
|
|
||||||
netWorth: 142910,
|
|
||||||
points: 10020,
|
|
||||||
shares: 200,
|
|
||||||
dailyChange: 5420,
|
|
||||||
dailyChangePercent: 0.0379259673920649359736897347981,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 2,
|
|
||||||
name: "notohh",
|
|
||||||
netWorth: 153495392,
|
|
||||||
points: 10020,
|
|
||||||
shares: 2432,
|
|
||||||
dailyChange: 0,
|
|
||||||
dailyChangePercent: 0,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 3,
|
|
||||||
name: "SecondSockSan",
|
|
||||||
netWorth: 153495,
|
|
||||||
points: 15020,
|
|
||||||
shares: 20,
|
|
||||||
dailyChange: -10432,
|
|
||||||
dailyChangePercent: -0.06796312583471774324896576435715,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 0,
|
|
||||||
name: "e__n__t__e",
|
|
||||||
netWorth: 429481824,
|
|
||||||
points: 1002022,
|
|
||||||
shares: 94214,
|
|
||||||
dailyChange: 329444422,
|
|
||||||
dailyChangePercent: 4.2932124926634939999741296760186,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 5,
|
|
||||||
name: "luckytohavefoundyou14252",
|
|
||||||
netWorth: 8024,
|
|
||||||
points: 423,
|
|
||||||
shares: 4,
|
|
||||||
dailyChange: 9,
|
|
||||||
dailyChangePercent: 0.00112163509471585244267198404786,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 6,
|
|
||||||
name: "ZeroxZerich",
|
|
||||||
netWorth: 842190,
|
|
||||||
points: 88542,
|
|
||||||
shares: 532,
|
|
||||||
dailyChange: -10219,
|
|
||||||
dailyChangePercent: -0.01213384153219582279533121979601,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 7,
|
|
||||||
name: "joeeyo",
|
|
||||||
netWorth: 10000000,
|
|
||||||
points: 9999979,
|
|
||||||
shares: 1,
|
|
||||||
dailyChange: 1,
|
|
||||||
dailyChangePercent: 0.0000001,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 8,
|
|
||||||
name: "dd_maru",
|
|
||||||
netWorth: 10328421,
|
|
||||||
points: 328421,
|
|
||||||
shares: 252,
|
|
||||||
dailyChange: 85192,
|
|
||||||
dailyChangePercent: 0.00824830823607984221402284047097,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 9,
|
|
||||||
name: "Goldeneye128",
|
|
||||||
netWorth: 58292,
|
|
||||||
points: 6521,
|
|
||||||
shares: 63,
|
|
||||||
dailyChange: -1942,
|
|
||||||
dailyChangePercent: -0.03331503465312564331297605160228,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 10,
|
|
||||||
name: "lilpastatv",
|
|
||||||
netWorth: 7328919,
|
|
||||||
points: 40,
|
|
||||||
shares: 93,
|
|
||||||
dailyChange: 921821,
|
|
||||||
dailyChangePercent: 0.12577857662228222197571019682439,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 11,
|
|
||||||
name: "domiswitch",
|
|
||||||
netWorth: 43290,
|
|
||||||
points: 5002,
|
|
||||||
shares: 15,
|
|
||||||
dailyChange: 2429,
|
|
||||||
dailyChangePercent: 0.05610995610995610995610995610996,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 12,
|
|
||||||
name: "minosura",
|
|
||||||
netWorth: 904328,
|
|
||||||
points: 32901,
|
|
||||||
shares: 83,
|
|
||||||
dailyChange: 94821,
|
|
||||||
dailyChangePercent: 0.10485244291894091524314186887943,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 13,
|
|
||||||
name: "scienceteam_member",
|
|
||||||
netWorth: 34894,
|
|
||||||
points: 958,
|
|
||||||
shares: 5,
|
|
||||||
dailyChange: -7964,
|
|
||||||
dailyChangePercent: -0.22823408035765461110792686421734,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 14,
|
|
||||||
name: "witchdev",
|
|
||||||
netWorth: 94382912,
|
|
||||||
points: 8532,
|
|
||||||
shares: 329,
|
|
||||||
dailyChange: -421,
|
|
||||||
dailyChangePercent: -0.0000044605531984433792422085896,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 15,
|
|
||||||
name: "justone123879",
|
|
||||||
netWorth: 8889123,
|
|
||||||
points: 86333,
|
|
||||||
shares: 153,
|
|
||||||
dailyChange: 53289,
|
|
||||||
dailyChangePercent: 0.00599485461051669551653183334284,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 16,
|
|
||||||
name: "marcelr_",
|
|
||||||
netWorth: 400329,
|
|
||||||
points: 39291,
|
|
||||||
shares: 52,
|
|
||||||
dailyChange: 1329,
|
|
||||||
dailyChangePercent: 0.00331976948959480827019776234047,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 17,
|
|
||||||
name: "fossabot",
|
|
||||||
netWorth: 20005,
|
|
||||||
points: 0,
|
|
||||||
shares: 1,
|
|
||||||
dailyChange: -31042,
|
|
||||||
dailyChangePercent: -1.5517120719820044988752811797051,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export type { fakeDataEntry };
|
|
856
pages/api/fakeUsers.ts
Normal file
856
pages/api/fakeUsers.ts
Normal file
|
@ -0,0 +1,856 @@
|
||||||
|
import type { NextApiRequest, NextApiResponse } from "next";
|
||||||
|
import { createRedisInstance } from "../../misc/redis";
|
||||||
|
import { getUserByName } from "../../misc/TwitchAPI";
|
||||||
|
import { fakePrices } from "./fakePrices";
|
||||||
|
|
||||||
|
type Data = {
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default async function handler(
|
||||||
|
req: NextApiRequest,
|
||||||
|
res: NextApiResponse<Data>
|
||||||
|
) {
|
||||||
|
const username = req.query.u ? (req.query.u as string) : undefined;
|
||||||
|
const sortBy = req.query.s ? (req.query.s as string) : undefined;
|
||||||
|
const sortAsc = req.query.a ? (req.query.a as string) : undefined;
|
||||||
|
|
||||||
|
const redis = createRedisInstance();
|
||||||
|
|
||||||
|
let data = fakeData;
|
||||||
|
// calculate all net worths
|
||||||
|
data = data.map((user) => {
|
||||||
|
return {
|
||||||
|
...user,
|
||||||
|
net_worth:
|
||||||
|
user.points +
|
||||||
|
user.assets.reduce(
|
||||||
|
(a, b) => a + b.count * (fakePrices[b.name] ?? 0),
|
||||||
|
0
|
||||||
|
),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
// calculate ranking based on net worth
|
||||||
|
data = data.sort((a, b) => (b.net_worth ?? 0) - (a.net_worth ?? 0));
|
||||||
|
data = data.map((user, i) => {
|
||||||
|
return {
|
||||||
|
...user,
|
||||||
|
rank: i + 1,
|
||||||
|
// calculate total assets held (shares)
|
||||||
|
shares: user.assets.reduce((a, b) => a + b.count, 0),
|
||||||
|
// sort users badges by priority
|
||||||
|
badges: (user.badges ?? []).sort((a, b) => b.priority - a.priority ?? 0),
|
||||||
|
// sort users assets by total value
|
||||||
|
assets: user.assets.sort(
|
||||||
|
(a, b) =>
|
||||||
|
(fakePrices[b.name] ?? 0) * b.count -
|
||||||
|
(fakePrices[a.name] ?? 0) * a.count
|
||||||
|
),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// if username is specified, only return that user
|
||||||
|
if (username) {
|
||||||
|
// if user does not exist, return error
|
||||||
|
data = data.filter((u) => u.name === username);
|
||||||
|
if (data.length === 0) {
|
||||||
|
res
|
||||||
|
.status(404)
|
||||||
|
.json({ error: { message: "User not found", code: 20000 } });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// get twitch data for user
|
||||||
|
let twitchData: { data: { [key: string]: any }[] };
|
||||||
|
try {
|
||||||
|
twitchData = await getUserByName(redis, username);
|
||||||
|
} catch (e) {
|
||||||
|
res.status(500).json({
|
||||||
|
error: { message: "Twitch or internal API is down", code: 10100 },
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// if data is empty, user does not exist
|
||||||
|
if (twitchData.data.length === 0) {
|
||||||
|
// temp who cares
|
||||||
|
twitchData.data[0] = {};
|
||||||
|
twitchData.data[0].profile_image_url = "/img/logo.webp";
|
||||||
|
}
|
||||||
|
// add users profile picture url
|
||||||
|
data = data.map((u) => {
|
||||||
|
return {
|
||||||
|
...u,
|
||||||
|
avatar_url: twitchData.data[0].profile_image_url ?? "",
|
||||||
|
};
|
||||||
|
});
|
||||||
|
res.status(200).json({ data: data[0] });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (sortBy) {
|
||||||
|
if (sortBy === "daily_change") {
|
||||||
|
data = data.sort((a, b) => b.daily_change - a.daily_change);
|
||||||
|
} else if (sortBy === "daily_change_percent") {
|
||||||
|
data = data.sort(
|
||||||
|
(a, b) => b.daily_change_percent - a.daily_change_percent
|
||||||
|
);
|
||||||
|
} else if (sortBy === "shares") {
|
||||||
|
data = data.sort((a, b) => (b.shares ?? 0) - (a.shares ?? 0));
|
||||||
|
} else if (sortBy === "points") {
|
||||||
|
data = data.sort((a, b) => b.points - a.points);
|
||||||
|
} else if (sortBy === "name") {
|
||||||
|
data = data.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
|
}
|
||||||
|
if (sortAsc === "true") {
|
||||||
|
// slow but only needed for temporary fake data anyway
|
||||||
|
data = data.reverse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// fake loading time
|
||||||
|
await new Promise((resolve) =>
|
||||||
|
setTimeout(resolve, 250 + Math.random() * 1000)
|
||||||
|
);
|
||||||
|
res.status(200).json({ data: data });
|
||||||
|
}
|
||||||
|
|
||||||
|
interface asset {
|
||||||
|
name: string;
|
||||||
|
count: number;
|
||||||
|
provider: "7tv" | "bttv" | "ffz" | "ttv";
|
||||||
|
}
|
||||||
|
interface fakeDataEntry {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
points: number;
|
||||||
|
daily_change: number;
|
||||||
|
daily_change_percent: number;
|
||||||
|
assets: asset[];
|
||||||
|
net_worth?: number;
|
||||||
|
shares?: number;
|
||||||
|
avatar_url?: string;
|
||||||
|
badges?: badge[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface badge {
|
||||||
|
name: string;
|
||||||
|
color: string;
|
||||||
|
priority: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const adminBadge: badge = {
|
||||||
|
name: "Admin",
|
||||||
|
color: "#CC3333",
|
||||||
|
priority: 99999,
|
||||||
|
};
|
||||||
|
|
||||||
|
const CEOBadge: badge = {
|
||||||
|
name: "CEO",
|
||||||
|
color: "#F97316",
|
||||||
|
priority: 100000,
|
||||||
|
};
|
||||||
|
|
||||||
|
const webDevBadge: badge = {
|
||||||
|
name: "Web Dev",
|
||||||
|
color: "#a855f7",
|
||||||
|
priority: 50000,
|
||||||
|
};
|
||||||
|
|
||||||
|
const botDevBadge: badge = {
|
||||||
|
name: "Bot Dev",
|
||||||
|
color: "#48b2f1",
|
||||||
|
priority: 50001,
|
||||||
|
};
|
||||||
|
|
||||||
|
const fakeData: fakeDataEntry[] = [
|
||||||
|
{
|
||||||
|
id: 4,
|
||||||
|
name: "3zachm",
|
||||||
|
points: 7420, // uninvested points
|
||||||
|
daily_change: -500,
|
||||||
|
daily_change_percent: -0.0498504486540378863409770687936,
|
||||||
|
assets: [
|
||||||
|
{
|
||||||
|
name: "JIGACHAD",
|
||||||
|
count: 420,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "annykiss",
|
||||||
|
count: 8,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "HUH",
|
||||||
|
count: 1,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "annytfSigh",
|
||||||
|
count: 1,
|
||||||
|
provider: "ttv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "GabeN",
|
||||||
|
count: 3,
|
||||||
|
provider: "bttv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "widepeepoBlanket",
|
||||||
|
count: 1,
|
||||||
|
provider: "ffz",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "plink",
|
||||||
|
count: 1,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
badges: [adminBadge, webDevBadge],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: "ModulatingForce",
|
||||||
|
points: 10020,
|
||||||
|
daily_change: 5420,
|
||||||
|
daily_change_percent: 0.0379259673920649359736897347981,
|
||||||
|
assets: [
|
||||||
|
{
|
||||||
|
name: "OhTheMiseryEverybodyWantsToBeMyEnemySpareTheSympathyEverybodyWantsToBeMyEnemy-y-y-y-y",
|
||||||
|
count: 39,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Clueless",
|
||||||
|
count: 727,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "AnnySilly",
|
||||||
|
count: 4,
|
||||||
|
provider: "bttv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "annytfHeart",
|
||||||
|
count: 98,
|
||||||
|
provider: "ttv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Catge",
|
||||||
|
count: 4,
|
||||||
|
provider: "ffz",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
badges: [adminBadge, botDevBadge],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: "notohh",
|
||||||
|
points: 10020,
|
||||||
|
daily_change: 0,
|
||||||
|
daily_change_percent: 0,
|
||||||
|
assets: [
|
||||||
|
{
|
||||||
|
name: "YourMom",
|
||||||
|
count: 81,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "CumTime",
|
||||||
|
count: 92,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "KissaVei",
|
||||||
|
count: 1,
|
||||||
|
provider: "bttv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "SNIFFA",
|
||||||
|
count: 1219,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "FeelsBirthdayMan",
|
||||||
|
count: 1,
|
||||||
|
provider: "ffz",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "annytfRave",
|
||||||
|
count: 5,
|
||||||
|
provider: "ttv",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
badges: [adminBadge, botDevBadge],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
name: "SecondSockSan",
|
||||||
|
points: 15020,
|
||||||
|
daily_change: -10432,
|
||||||
|
daily_change_percent: -0.06796312583471774324896576435715,
|
||||||
|
assets: [
|
||||||
|
{
|
||||||
|
name: "AYAYAjam",
|
||||||
|
count: 46,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "GabeN",
|
||||||
|
count: 3,
|
||||||
|
provider: "bttv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ThisStream",
|
||||||
|
count: 210,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "BAND",
|
||||||
|
count: 91,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "annytfMelt",
|
||||||
|
count: 16,
|
||||||
|
provider: "ttv",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
badges: [CEOBadge, adminBadge],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 0,
|
||||||
|
name: "mzntori",
|
||||||
|
points: 922022,
|
||||||
|
daily_change: 329444422,
|
||||||
|
daily_change_percent: 4.2932124926634939999741296760186,
|
||||||
|
assets: [
|
||||||
|
{
|
||||||
|
name: "peepoSnow",
|
||||||
|
count: 72,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "annyHop",
|
||||||
|
count: 61,
|
||||||
|
provider: "bttv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "annyExcitedHug",
|
||||||
|
count: 26,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "AAAA",
|
||||||
|
count: 65,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "peepoWTF",
|
||||||
|
count: 60,
|
||||||
|
provider: "ffz",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "annytfAngy",
|
||||||
|
count: 90,
|
||||||
|
provider: "ttv",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
badges: [adminBadge, botDevBadge],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 5,
|
||||||
|
name: "luckytohavefoundyou14252",
|
||||||
|
points: 423,
|
||||||
|
daily_change: 9,
|
||||||
|
daily_change_percent: 0.00112163509471585244267198404786,
|
||||||
|
assets: [
|
||||||
|
{
|
||||||
|
name: "HACKERMANS",
|
||||||
|
count: 59,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "THIS",
|
||||||
|
count: 70,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "lebronJAM",
|
||||||
|
count: 66,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 6,
|
||||||
|
name: "ZeroxZerich",
|
||||||
|
points: 88542,
|
||||||
|
daily_change: -10219,
|
||||||
|
daily_change_percent: -0.01213384153219582279533121979601,
|
||||||
|
assets: [
|
||||||
|
{
|
||||||
|
name: "WeebRun",
|
||||||
|
count: 10,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "annySaur",
|
||||||
|
count: 7,
|
||||||
|
provider: "bttv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "BAND",
|
||||||
|
count: 49,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "SNIFFA",
|
||||||
|
count: 78,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "PepegaPhone",
|
||||||
|
count: 142,
|
||||||
|
provider: "ffz",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "annytfHug",
|
||||||
|
count: 19,
|
||||||
|
provider: "ttv",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 7,
|
||||||
|
name: "joeeyo",
|
||||||
|
points: 99979,
|
||||||
|
daily_change: 1,
|
||||||
|
daily_change_percent: 0.0000001,
|
||||||
|
assets: [
|
||||||
|
{
|
||||||
|
name: "Siti",
|
||||||
|
count: 32,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "annytfLUL",
|
||||||
|
count: 9,
|
||||||
|
provider: "ttv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "peepoSnow",
|
||||||
|
count: 37,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "MadgeJuice",
|
||||||
|
count: 70,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "annyBlankies",
|
||||||
|
count: 88,
|
||||||
|
provider: "bttv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "TWINGO",
|
||||||
|
count: 98,
|
||||||
|
provider: "ffz",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 8,
|
||||||
|
name: "dd_maru",
|
||||||
|
points: 208421,
|
||||||
|
daily_change: 85192,
|
||||||
|
daily_change_percent: 0.00824830823607984221402284047097,
|
||||||
|
assets: [
|
||||||
|
{
|
||||||
|
name: "BocchiPossessed",
|
||||||
|
count: 56,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "toffeeConfused",
|
||||||
|
count: 64,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "annytfBanana",
|
||||||
|
count: 15,
|
||||||
|
provider: "bttv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ewLeague",
|
||||||
|
count: 64,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "annytfPain",
|
||||||
|
count: 37,
|
||||||
|
provider: "ttv",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 9,
|
||||||
|
name: "Goldeneye128",
|
||||||
|
points: 6521,
|
||||||
|
daily_change: -1942,
|
||||||
|
daily_change_percent: -0.03331503465312564331297605160228,
|
||||||
|
assets: [
|
||||||
|
{
|
||||||
|
name: "PagMan",
|
||||||
|
count: 52,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "CapybaraStare",
|
||||||
|
count: 47,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "GabeN",
|
||||||
|
count: 52,
|
||||||
|
provider: "bttv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "GroupWankge",
|
||||||
|
count: 38,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "annyCucumber",
|
||||||
|
count: 90,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "annytfKnuckles",
|
||||||
|
count: 2,
|
||||||
|
provider: "ttv",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 10,
|
||||||
|
name: "lilpastatv",
|
||||||
|
points: 40,
|
||||||
|
daily_change: 921821,
|
||||||
|
daily_change_percent: 0.12577857662228222197571019682439,
|
||||||
|
assets: [
|
||||||
|
{
|
||||||
|
name: "Wigglecat",
|
||||||
|
count: 205,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "guraWink",
|
||||||
|
count: 5,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "annyPls",
|
||||||
|
count: 5,
|
||||||
|
provider: "bttv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "golive",
|
||||||
|
count: 46,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "COPIUM",
|
||||||
|
count: 82,
|
||||||
|
provider: "ffz",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "annytfCheer",
|
||||||
|
count: 54,
|
||||||
|
provider: "ttv",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 11,
|
||||||
|
name: "domiswitch",
|
||||||
|
points: 5002,
|
||||||
|
daily_change: 2429,
|
||||||
|
daily_change_percent: 0.05610995610995610995610995610996,
|
||||||
|
assets: [
|
||||||
|
{
|
||||||
|
name: "peepoFlute",
|
||||||
|
count: 81,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "WhoAsked",
|
||||||
|
count: 44,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "pL",
|
||||||
|
count: 24,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "peepoSnow",
|
||||||
|
count: 13,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "annytfBlink",
|
||||||
|
count: 10,
|
||||||
|
provider: "bttv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "annytfBonk",
|
||||||
|
count: 77,
|
||||||
|
provider: "ttv",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 12,
|
||||||
|
name: "minosura",
|
||||||
|
points: 32901,
|
||||||
|
daily_change: 94821,
|
||||||
|
daily_change_percent: 0.10485244291894091524314186887943,
|
||||||
|
assets: [
|
||||||
|
{
|
||||||
|
name: "Okayeg",
|
||||||
|
count: 100,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "burh",
|
||||||
|
count: 100,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "annyHop",
|
||||||
|
count: 16,
|
||||||
|
provider: "bttv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "AndKnuckles",
|
||||||
|
count: 17,
|
||||||
|
provider: "ffz",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "yoshiJAM",
|
||||||
|
count: 67,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "WhoAsked",
|
||||||
|
count: 59,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "annytfSit",
|
||||||
|
count: 53,
|
||||||
|
provider: "ttv",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 13,
|
||||||
|
name: "scienceteam_member",
|
||||||
|
points: 958,
|
||||||
|
daily_change: -7964,
|
||||||
|
daily_change_percent: -0.22823408035765461110792686421734,
|
||||||
|
assets: [
|
||||||
|
{
|
||||||
|
name: "LULE",
|
||||||
|
count: 43,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Madgeclap",
|
||||||
|
count: 82,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "annyDFast",
|
||||||
|
count: 22,
|
||||||
|
provider: "bttv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "PeepoKittyHug",
|
||||||
|
count: 7,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 14,
|
||||||
|
name: "witchdev",
|
||||||
|
points: 8532,
|
||||||
|
daily_change: -421,
|
||||||
|
daily_change_percent: -0.0000044605531984433792422085896,
|
||||||
|
assets: [
|
||||||
|
{
|
||||||
|
name: "SNIFFA",
|
||||||
|
count: 76,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "annyCD",
|
||||||
|
count: 62,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "annyBlankies",
|
||||||
|
count: 74,
|
||||||
|
provider: "bttv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "anyatf",
|
||||||
|
count: 24,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "annytfGamba",
|
||||||
|
count: 32,
|
||||||
|
provider: "ttv",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 15,
|
||||||
|
name: "justone123879",
|
||||||
|
points: 86333,
|
||||||
|
daily_change: 53289,
|
||||||
|
daily_change_percent: 0.00599485461051669551653183334284,
|
||||||
|
assets: [
|
||||||
|
{
|
||||||
|
name: "Homi",
|
||||||
|
count: 9,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "wideVIBE",
|
||||||
|
count: 61,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Annie",
|
||||||
|
count: 24,
|
||||||
|
provider: "bttv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Lagging",
|
||||||
|
count: 92,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "annytfFlower",
|
||||||
|
count: 33,
|
||||||
|
provider: "ttv",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 16,
|
||||||
|
name: "marcelr_",
|
||||||
|
points: 39291,
|
||||||
|
daily_change: 1329,
|
||||||
|
daily_change_percent: 0.00331976948959480827019776234047,
|
||||||
|
assets: [
|
||||||
|
{
|
||||||
|
name: "peepoStuck",
|
||||||
|
count: 91,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "PokiShare",
|
||||||
|
count: 13,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "VeryBased",
|
||||||
|
count: 7,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "annyHopper",
|
||||||
|
count: 24,
|
||||||
|
provider: "bttv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "annytfFlower",
|
||||||
|
count: 79,
|
||||||
|
provider: "ttv",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 17,
|
||||||
|
name: "fossabot",
|
||||||
|
points: 0,
|
||||||
|
daily_change: -31042,
|
||||||
|
daily_change_percent: -1.5517120719820044988752811797051,
|
||||||
|
assets: [
|
||||||
|
{
|
||||||
|
name: "catbaby",
|
||||||
|
count: 41,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "peepoCat",
|
||||||
|
count: 41,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "plink",
|
||||||
|
count: 32,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "AngelThump",
|
||||||
|
count: 41,
|
||||||
|
provider: "bttv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "annytfSad",
|
||||||
|
count: 2,
|
||||||
|
provider: "ttv",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 18,
|
||||||
|
name: "Headdesking1",
|
||||||
|
points: 429,
|
||||||
|
daily_change: 0,
|
||||||
|
daily_change_percent: 0,
|
||||||
|
assets: [
|
||||||
|
{
|
||||||
|
name: "anyaPls",
|
||||||
|
count: 92,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "toffeeDinkDonk",
|
||||||
|
count: 6,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "SoCute",
|
||||||
|
count: 99,
|
||||||
|
provider: "7tv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "annyBlankies",
|
||||||
|
count: 42,
|
||||||
|
provider: "bttv",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "annytfHeart",
|
||||||
|
count: 63,
|
||||||
|
provider: "ttv",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export type { fakeDataEntry };
|
30
pages/api/ffz/emotes.ts
Normal file
30
pages/api/ffz/emotes.ts
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import type { NextApiRequest, NextApiResponse } from "next";
|
||||||
|
import { createRedisInstance } from "../../../misc/redis";
|
||||||
|
import { getEmoteSet, getGlobalEmotes } from "../../../misc/FFZAPI";
|
||||||
|
|
||||||
|
type Data = {
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default async function handler(
|
||||||
|
req: NextApiRequest,
|
||||||
|
res: NextApiResponse<Data>
|
||||||
|
) {
|
||||||
|
const redis = createRedisInstance();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const channel = req.query.s
|
||||||
|
? (await getEmoteSet(redis, req.query.s as string)).set.emoticons
|
||||||
|
: undefined;
|
||||||
|
let global = await getGlobalEmotes(redis);
|
||||||
|
// set global emotes to be the three sets within the global object ("3", "4330")
|
||||||
|
global = global.sets["3"].emoticons.concat(global.sets["4330"].emoticons);
|
||||||
|
redis.quit();
|
||||||
|
res.status(200).json({ channel, global });
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
res
|
||||||
|
.status(500)
|
||||||
|
.json({ error: { message: "FFZ or internal API is down", code: 10300 } });
|
||||||
|
}
|
||||||
|
}
|
30
pages/api/twitch/emotes.ts
Normal file
30
pages/api/twitch/emotes.ts
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import type { NextApiRequest, NextApiResponse } from "next";
|
||||||
|
import { createRedisInstance } from "../../../misc/redis";
|
||||||
|
import { getChannelEmotes, getGlobalEmotes } from "../../../misc/TwitchAPI";
|
||||||
|
|
||||||
|
type Data = {
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default async function handler(
|
||||||
|
req: NextApiRequest,
|
||||||
|
res: NextApiResponse<Data>
|
||||||
|
) {
|
||||||
|
const redis = createRedisInstance();
|
||||||
|
|
||||||
|
try {
|
||||||
|
const channel = req.query.c
|
||||||
|
? (await getChannelEmotes(redis, req.query.c as string)).data
|
||||||
|
: undefined;
|
||||||
|
const global = (await getGlobalEmotes(redis)).data;
|
||||||
|
redis.quit();
|
||||||
|
res.status(200).json({ channel, global });
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
res
|
||||||
|
.status(500)
|
||||||
|
.json({
|
||||||
|
error: { message: "Twitch or internal API is down", code: 10100 },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,11 +2,10 @@ import { m } from "framer-motion";
|
||||||
import { ReactElement, useEffect, useState } from "react";
|
import { ReactElement, useEffect, useState } from "react";
|
||||||
import HomeLayout from "../layouts/HomeLayout";
|
import HomeLayout from "../layouts/HomeLayout";
|
||||||
import { homeMain } from "../layouts/NavTemplates";
|
import { homeMain } from "../layouts/NavTemplates";
|
||||||
import type { NextPageWithLayout } from "./_app";
|
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
|
|
||||||
const Home: NextPageWithLayout = () => {
|
function Home() {
|
||||||
let api7tvEmotes = `/api/7tv/emotes?c=61ad997effa9aba101bcfddf`;
|
let api7tvEmotes = `/api/7tv/emotes?c=61ad997effa9aba101bcfddf`;
|
||||||
const [emotesUrls, setEmotes] = useState([]);
|
const [emotesUrls, setEmotes] = useState([]);
|
||||||
const [currentEmote, setCurrentEmote] = useState(0);
|
const [currentEmote, setCurrentEmote] = useState(0);
|
||||||
|
@ -15,6 +14,10 @@ const Home: NextPageWithLayout = () => {
|
||||||
fetch(api7tvEmotes)
|
fetch(api7tvEmotes)
|
||||||
.then((res) => res.json())
|
.then((res) => res.json())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
|
// if error, return
|
||||||
|
if (data.error) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
// get all emote URLs
|
// get all emote URLs
|
||||||
let emoteUrls = data.channel.user.emote_sets[0].emotes.map(
|
let emoteUrls = data.channel.user.emote_sets[0].emotes.map(
|
||||||
(emote: any) => {
|
(emote: any) => {
|
||||||
|
@ -79,49 +82,25 @@ const Home: NextPageWithLayout = () => {
|
||||||
<title>Home - toffee</title>
|
<title>Home - toffee</title>
|
||||||
</Head>
|
</Head>
|
||||||
<div className="flex h-full w-full flex-col items-center justify-center">
|
<div className="flex h-full w-full flex-col items-center justify-center">
|
||||||
<div className="inline-grid grid-cols-1 gap-10 text-white md:grid-cols-3">
|
<div className="inline-grid grid-cols-1 gap-20 text-white md:grid-cols-3">
|
||||||
<m.div
|
<m.div
|
||||||
className="flex flex-col from-purple-400 to-pink-600 font-plusJakarta text-7xl font-semibold sm:text-8xl md:col-span-2"
|
className="flex flex-col from-purple-400 to-pink-600 font-plusJakarta md:col-span-2"
|
||||||
variants={sloganContainerVariants}
|
variants={sloganContainerVariants}
|
||||||
initial="initial"
|
initial="initial"
|
||||||
animate="animate"
|
animate="animate"
|
||||||
>
|
>
|
||||||
<m.div
|
<div className="flex flex-row text-8xl font-bold italic">
|
||||||
className="flex flex-row items-center"
|
<m.h1 variants={sloganHeaderVariants}>t</m.h1>
|
||||||
variants={sloganHeaderVariants}
|
<m.h1 className="text-orange-400" variants={sloganHeaderVariants}>
|
||||||
>
|
|
||||||
<h1 className="bg-gradient-to-b bg-clip-text text-transparent">
|
|
||||||
t
|
|
||||||
</h1>
|
|
||||||
<h1>ax-free</h1>
|
|
||||||
</m.div>
|
|
||||||
<m.div
|
|
||||||
className="flex flex-row items-center"
|
|
||||||
variants={sloganHeaderVariants}
|
|
||||||
>
|
|
||||||
<h1 className="bg-gradient-to-tl bg-clip-text text-transparent">
|
|
||||||
off
|
off
|
||||||
</h1>
|
</m.h1>
|
||||||
<h1>line</h1>
|
<m.h1 variants={sloganHeaderVariants}>ee</m.h1>
|
||||||
</m.div>
|
</div>
|
||||||
<m.div
|
<div className="text-xl italic">
|
||||||
className="flex flex-row items-center"
|
<m.h2 variants={sloganHeaderVariants}>
|
||||||
variants={sloganHeaderVariants}
|
a tax-free offline emote exchange utility
|
||||||
>
|
</m.h2>
|
||||||
<h1 className="bg-gradient-to-l bg-clip-text text-transparent">
|
</div>
|
||||||
e
|
|
||||||
</h1>
|
|
||||||
<h1>mote</h1>
|
|
||||||
</m.div>
|
|
||||||
<m.div
|
|
||||||
className="flex flex-row items-center"
|
|
||||||
variants={sloganHeaderVariants}
|
|
||||||
>
|
|
||||||
<h1 className="bg-gradient-to-bl bg-clip-text text-transparent">
|
|
||||||
e
|
|
||||||
</h1>
|
|
||||||
<h1>xchange</h1>
|
|
||||||
</m.div>
|
|
||||||
</m.div>
|
</m.div>
|
||||||
<m.div
|
<m.div
|
||||||
className="flex items-center justify-center"
|
className="flex items-center justify-center"
|
||||||
|
@ -146,7 +125,7 @@ const Home: NextPageWithLayout = () => {
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
}
|
||||||
|
|
||||||
const sloganContainerVariants = {
|
const sloganContainerVariants = {
|
||||||
initial: {
|
initial: {
|
||||||
|
@ -163,7 +142,7 @@ const sloganContainerVariants = {
|
||||||
bounce: 0.5,
|
bounce: 0.5,
|
||||||
stiffness: 150,
|
stiffness: 150,
|
||||||
delayChildren: 1.0,
|
delayChildren: 1.0,
|
||||||
staggerChildren: 0.45,
|
staggerChildren: 0.1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -171,9 +150,11 @@ const sloganContainerVariants = {
|
||||||
const sloganHeaderVariants = {
|
const sloganHeaderVariants = {
|
||||||
initial: {
|
initial: {
|
||||||
opacity: 0,
|
opacity: 0,
|
||||||
|
y: -15,
|
||||||
},
|
},
|
||||||
animate: {
|
animate: {
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
|
y: 0,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import { m, Variants } from "framer-motion";
|
import { m, Variants } from "framer-motion";
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
|
import Link from "next/link";
|
||||||
import { ReactElement, useEffect, useState } from "react";
|
import { ReactElement, useEffect, useState } from "react";
|
||||||
import Loading from "../../components/common/Loading";
|
import Loading from "../../components/common/Loading";
|
||||||
import DashLayout from "../../layouts/DashLayout";
|
import DashLayout from "../../layouts/DashLayout";
|
||||||
import { fakeDataEntry } from "../api/fakeRanking";
|
import { fakeDataEntry } from "../api/fakeUsers";
|
||||||
|
|
||||||
function Ranking() {
|
function Ranking() {
|
||||||
const [sortBy, setSortBy] = useState("netWorth");
|
const [sortBy, setSortBy] = useState("netWorth");
|
||||||
|
@ -14,7 +15,7 @@ function Ranking() {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setDataLoaded(false);
|
setDataLoaded(false);
|
||||||
// fetch data from api on change to sort method
|
// fetch data from api on change to sort method
|
||||||
fetch(`/api/fakeRanking?s=${sortBy}&a=${sortAsc}`)
|
fetch(`/api/fakeUsers?s=${sortBy}&a=${sortAsc}`)
|
||||||
.then((res) => res.json())
|
.then((res) => res.json())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
setFakeData(data.data);
|
setFakeData(data.data);
|
||||||
|
@ -78,13 +79,13 @@ function Ranking() {
|
||||||
<title>Ranking - toffee</title>
|
<title>Ranking - toffee</title>
|
||||||
</Head>
|
</Head>
|
||||||
<div className="flex w-full justify-center">
|
<div className="flex w-full justify-center">
|
||||||
<div className="ml-3 flex w-full flex-col items-center justify-start font-robotoMono font-semibold lg:ml-0">
|
<div className="ml-3 flex w-full max-w-7xl flex-col items-center justify-start font-plusJakarta font-semibold lg:ml-0">
|
||||||
{/* hidden if smaller than lg */}
|
{/* hidden if smaller than lg */}
|
||||||
<m.h1
|
<m.h1
|
||||||
className="hidden bg-gradient-to-tr from-purple-500 to-purple-100 bg-clip-text py-10 text-center font-plusJakarta text-5xl font-bold text-white text-transparent lg:block lg:text-6xl"
|
className="hidden py-10 text-center text-5xl font-normal text-pink-300 lg:block lg:text-6xl"
|
||||||
variants={headerVariants}
|
variants={headerVariants}
|
||||||
>
|
>
|
||||||
Top Investors
|
top investors
|
||||||
</m.h1>
|
</m.h1>
|
||||||
{/* TODO: responsive for extremely skinny displays (i.e. galaxy fold), or really for mobile entirely so info is not lost */}
|
{/* TODO: responsive for extremely skinny displays (i.e. galaxy fold), or really for mobile entirely so info is not lost */}
|
||||||
<m.div
|
<m.div
|
||||||
|
@ -162,39 +163,47 @@ function Ranking() {
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
// generate table rows
|
// generate table rows
|
||||||
fakeData.map((entry: fakeDataEntry, index) => {
|
fakeData.map(
|
||||||
// if daily change is negative, make it red
|
(entry: { [key: string]: any }, index: number) => {
|
||||||
let changeClass = " text-lime-500";
|
// if daily change is negative, make it red
|
||||||
if (entry.dailyChangePercent < 0) {
|
let changeClass = " text-lime-500";
|
||||||
changeClass = " text-red-500";
|
if (entry.daily_change_percent < 0) {
|
||||||
|
changeClass = " text-red-500";
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<m.div
|
||||||
|
className="inline-grid w-full grid-flow-col grid-cols-[1fr_4fr_3fr_2fr] gap-2 border-b-2 border-zinc-700 px-5 py-2 text-right md:grid-cols-[0.5fr_4fr_repeat(3,_2fr)_1.5fr]"
|
||||||
|
key={entry.id}
|
||||||
|
variants={rankingDataLineVariants}
|
||||||
|
>
|
||||||
|
<h1 className="text-left md:text-center">
|
||||||
|
{index + 1}
|
||||||
|
</h1>
|
||||||
|
<Link
|
||||||
|
href={`/user/${entry.name}`}
|
||||||
|
className="overflow-hidden"
|
||||||
|
>
|
||||||
|
<h1 className="overflow-hidden overflow-ellipsis whitespace-nowrap text-left">
|
||||||
|
{entry.name}
|
||||||
|
</h1>
|
||||||
|
</Link>
|
||||||
|
<h1>{entry.net_worth.toLocaleString("en-US")}</h1>
|
||||||
|
<h1 className="hidden md:block">
|
||||||
|
{entry.points.toLocaleString("en-US")}
|
||||||
|
</h1>
|
||||||
|
<h1 className="hidden md:block">
|
||||||
|
{entry.shares.toLocaleString("en-US")}
|
||||||
|
</h1>
|
||||||
|
<h1 className={changeClass}>
|
||||||
|
{(
|
||||||
|
Math.round(entry.daily_change_percent * 1000) /
|
||||||
|
10
|
||||||
|
).toFixed(1) + "%"}
|
||||||
|
</h1>
|
||||||
|
</m.div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return (
|
)
|
||||||
<m.div
|
|
||||||
className="inline-grid w-full grid-flow-col grid-cols-[1fr_4fr_3fr_2fr] gap-2 border-b-2 border-zinc-700 px-5 py-2 text-right md:grid-cols-[0.5fr_4fr_repeat(3,_2fr)_1.5fr]"
|
|
||||||
key={entry.id}
|
|
||||||
variants={rankingDataLineVariants}
|
|
||||||
>
|
|
||||||
<h1 className="text-left md:text-center">
|
|
||||||
{index + 1}
|
|
||||||
</h1>
|
|
||||||
<h1 className="overflow-hidden overflow-ellipsis whitespace-nowrap text-left">
|
|
||||||
{entry.name}
|
|
||||||
</h1>
|
|
||||||
<h1>{entry.netWorth.toLocaleString("en-US")}</h1>
|
|
||||||
<h1 className="hidden md:block">
|
|
||||||
{entry.points.toLocaleString("en-US")}
|
|
||||||
</h1>
|
|
||||||
<h1 className="hidden md:block">
|
|
||||||
{entry.shares.toLocaleString("en-US")}
|
|
||||||
</h1>
|
|
||||||
<h1 className={changeClass}>
|
|
||||||
{(
|
|
||||||
Math.round(entry.dailyChangePercent * 1000) / 10
|
|
||||||
).toFixed(1) + "%"}
|
|
||||||
</h1>
|
|
||||||
</m.div>
|
|
||||||
);
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
</m.div>
|
</m.div>
|
||||||
)
|
)
|
486
pages/user/[username]/index.tsx
Normal file
486
pages/user/[username]/index.tsx
Normal file
|
@ -0,0 +1,486 @@
|
||||||
|
import { m } from "framer-motion";
|
||||||
|
import Head from "next/head";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
import { ReactElement, useEffect, useState } from "react";
|
||||||
|
import DashLayout from "../../../layouts/DashLayout";
|
||||||
|
import Image from "next/image";
|
||||||
|
import Loading from "../../../components/common/Loading";
|
||||||
|
|
||||||
|
// TODO: Animations
|
||||||
|
|
||||||
|
function UserPage() {
|
||||||
|
const [channelEmotes, setChannelEmotes] = useState<{
|
||||||
|
[key: string]: { [key: string]: string };
|
||||||
|
}>({});
|
||||||
|
const [userData, setUserData] = useState<{ [key: string]: any }>({});
|
||||||
|
const [errorCode, setErrorCode] = useState<number | null>(null);
|
||||||
|
const router = useRouter();
|
||||||
|
const { username } = router.query;
|
||||||
|
const title = username ? `${username} - toffee` : "toffee";
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!router.isReady) return;
|
||||||
|
fetch("/api/7tv/emotes?c=61ad997effa9aba101bcfddf")
|
||||||
|
.then((res) => res.json())
|
||||||
|
.then((data) => {
|
||||||
|
// if error, return
|
||||||
|
if (data.error) {
|
||||||
|
setErrorCode(data.error.code);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// construct js object with emote names as keys and emote urls as values
|
||||||
|
let emotes: { [key: string]: string } = {};
|
||||||
|
data.channel.user.emote_sets[0].emotes.forEach((emote: any) => {
|
||||||
|
let base_url = emote.data.host.url;
|
||||||
|
// get the largest emote size, append it to the base url
|
||||||
|
let largest = emote.data.host.files[emote.data.host.files.length - 1];
|
||||||
|
emotes[emote.data.name] = `https:${base_url}/${largest.name}`;
|
||||||
|
});
|
||||||
|
// same for global emotes
|
||||||
|
data.global.namedEmoteSet.emotes.forEach((emote: any) => {
|
||||||
|
let base_url = emote.data.host.url;
|
||||||
|
let largest = emote.data.host.files[emote.data.host.files.length - 1];
|
||||||
|
emotes[emote.data.name] = `https:${base_url}/${largest.name}`;
|
||||||
|
});
|
||||||
|
// set 7tv key to channelEmotes
|
||||||
|
setChannelEmotes((prev) => ({ ...prev, "7tv": emotes }));
|
||||||
|
});
|
||||||
|
fetch("/api/bttv/emotes?c=56418014")
|
||||||
|
.then((res) => res.json())
|
||||||
|
.then((data) => {
|
||||||
|
if (data.error) {
|
||||||
|
setErrorCode(data.error.code);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let emotes: { [key: string]: string } = {};
|
||||||
|
data.channel.forEach((emote: any) => {
|
||||||
|
emotes[emote.code] = `https://cdn.betterttv.net/emote/${emote.id}/3x`;
|
||||||
|
});
|
||||||
|
data.global.forEach((emote: any) => {
|
||||||
|
emotes[emote.code] = `https://cdn.betterttv.net/emote/${emote.id}/3x`;
|
||||||
|
});
|
||||||
|
// add as bttv key to channelEmotes
|
||||||
|
setChannelEmotes((prev) => ({ ...prev, bttv: emotes }));
|
||||||
|
});
|
||||||
|
fetch("/api/ffz/emotes?s=341402")
|
||||||
|
.then((res) => res.json())
|
||||||
|
.then((data) => {
|
||||||
|
if (data.error) {
|
||||||
|
setErrorCode(data.error.code);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let emotes: { [key: string]: string } = {};
|
||||||
|
data.channel.forEach((emote: any) => {
|
||||||
|
// ffz emotes don't have all sizes available, so we need to get the largest one by taking the largest key in the urls object
|
||||||
|
emotes[emote.name] = `https:${
|
||||||
|
emote.urls[
|
||||||
|
Math.max(...Object.keys(emote.urls).map((k) => parseInt(k)))
|
||||||
|
]
|
||||||
|
}`;
|
||||||
|
});
|
||||||
|
data.global.forEach((emote: any) => {
|
||||||
|
emotes[emote.name] = `https:${
|
||||||
|
emote.urls[
|
||||||
|
Math.max(...Object.keys(emote.urls).map((k) => parseInt(k)))
|
||||||
|
]
|
||||||
|
}`;
|
||||||
|
});
|
||||||
|
// add as ffz key to channelEmotes
|
||||||
|
setChannelEmotes((prev) => ({ ...prev, ffz: emotes }));
|
||||||
|
});
|
||||||
|
fetch("/api/twitch/emotes?c=56418014")
|
||||||
|
.then((res) => res.json())
|
||||||
|
.then((data) => {
|
||||||
|
if (data.error) {
|
||||||
|
setErrorCode(data.error.code);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let emotes: { [key: string]: string } = {};
|
||||||
|
data.channel.forEach((emote: any) => {
|
||||||
|
emotes[emote.name] = emote.images["url_4x"];
|
||||||
|
});
|
||||||
|
data.global.forEach((emote: any) => {
|
||||||
|
emotes[emote.name] = emote.images["url_4x"];
|
||||||
|
});
|
||||||
|
// add as twitch key to channelEmotes
|
||||||
|
setChannelEmotes((prev) => ({ ...prev, ttv: emotes }));
|
||||||
|
});
|
||||||
|
fetch(`/api/fakeUsers?u=${username}`)
|
||||||
|
.then((res) => res.json())
|
||||||
|
.then((data) => {
|
||||||
|
if (data.error) {
|
||||||
|
setErrorCode(data.error.code);
|
||||||
|
}
|
||||||
|
setUserData(data.data);
|
||||||
|
});
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [router.isReady]);
|
||||||
|
|
||||||
|
if (errorCode !== null) {
|
||||||
|
// 20000 = user not found
|
||||||
|
// 10000 = 7tv api error
|
||||||
|
// 10100 = Twitch api error
|
||||||
|
// 10200 = BTTV api error
|
||||||
|
// 10300 = FFZ api error
|
||||||
|
const errorMsg = errorCode === 20000 ? "User not found" : "API error";
|
||||||
|
return (
|
||||||
|
<m.div
|
||||||
|
className="flex h-screen w-full items-center justify-center text-3xl"
|
||||||
|
initial={{ opacity: 0, y: -50 }}
|
||||||
|
animate={{ opacity: 1, y: 0, transition: { duration: 1.0 } }}
|
||||||
|
exit={{ opacity: 0, y: -25 }}
|
||||||
|
>
|
||||||
|
<p>{errorMsg}</p>
|
||||||
|
</m.div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if json is empty, and if channelEmotes is incomplete, show loading screen
|
||||||
|
if (
|
||||||
|
Object.keys(channelEmotes).length < 4 ||
|
||||||
|
!userData ||
|
||||||
|
Object.keys(userData).length === 0
|
||||||
|
) {
|
||||||
|
return (
|
||||||
|
<div className="flex h-screen w-full items-center justify-center text-3xl">
|
||||||
|
<Loading />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
console.log(channelEmotes);
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Head>
|
||||||
|
<title>{title}</title>
|
||||||
|
<meta
|
||||||
|
name="description"
|
||||||
|
content={`${username}'s portfolio on toffee`}
|
||||||
|
/>
|
||||||
|
</Head>
|
||||||
|
<div className="flex justify-center">
|
||||||
|
<div className="mt-7 inline-grid w-[calc(100%-40px)] max-w-5xl grid-cols-10 gap-3 pl-2 font-plusJakarta lg:mt-12 lg:pl-0 lg:pr-2">
|
||||||
|
{/* User "banner" */}
|
||||||
|
<div className="col-span-10 mb-2 rounded-2xl bg-zinc-800 bg-opacity-70 p-3">
|
||||||
|
<div className="flex items-center justify-between p-4">
|
||||||
|
<div className="flex flex-row items-center">
|
||||||
|
<div className="relative bottom-[70px] w-[169px]">
|
||||||
|
<Image
|
||||||
|
src={userData.avatar_url}
|
||||||
|
alt="User avatar"
|
||||||
|
width={140}
|
||||||
|
height={140}
|
||||||
|
priority
|
||||||
|
className="absolute rounded-lg border-4"
|
||||||
|
style={{
|
||||||
|
borderColor: userData.badges[0]
|
||||||
|
? userData.badges[0].color
|
||||||
|
: "grey",
|
||||||
|
// "glow" effect
|
||||||
|
boxShadow: `0px 0px 20px 1px ${
|
||||||
|
userData.badges[0]
|
||||||
|
? userData.badges[0].color
|
||||||
|
: "transparent"
|
||||||
|
}`,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex-col">
|
||||||
|
<h1 className="text-4xl font-semibold text-white">
|
||||||
|
{userData.name}
|
||||||
|
</h1>
|
||||||
|
{/* User's badges */}
|
||||||
|
<div className="mt-1 flex flex-row text-sm">
|
||||||
|
{userData.badges ? (
|
||||||
|
userData.badges.map(
|
||||||
|
(badge: {
|
||||||
|
name: string;
|
||||||
|
color: string;
|
||||||
|
priority: number;
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{ backgroundColor: badge.color }}
|
||||||
|
className="mr-1 rounded-md bg-purple-500 px-2"
|
||||||
|
key={badge.name}
|
||||||
|
>
|
||||||
|
<span className="text-white">{badge.name}</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="hidden md:block">
|
||||||
|
<h1>
|
||||||
|
<span className="text-4xl font-semibold text-zinc-400">
|
||||||
|
$
|
||||||
|
</span>
|
||||||
|
<span className="text-4xl text-white">
|
||||||
|
{userData.net_worth.toLocaleString("en-US")}
|
||||||
|
</span>
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* Main Container */}
|
||||||
|
<div className="col-span-10 inline-grid grid-cols-7 gap-3 rounded-2xl lg:col-span-7">
|
||||||
|
{/* User's Rank/Graph */}
|
||||||
|
<div className="col-span-7 rounded-2xl bg-zinc-800 bg-opacity-70">
|
||||||
|
<div className="flex flex-row items-center justify-between p-5">
|
||||||
|
<div className="flex-col px-2">
|
||||||
|
<h1 className="mb-1 whitespace-nowrap text-center text-xl font-medium text-white underline">
|
||||||
|
Global Rank
|
||||||
|
</h1>
|
||||||
|
<div className="flex items-center text-3xl font-bold">
|
||||||
|
<span className="text-zinc-400">#</span>
|
||||||
|
<span className="text-white">
|
||||||
|
{userData.rank.toLocaleString("en-US")}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="hidden md:block">
|
||||||
|
<Image
|
||||||
|
src="/img/well_drawn_rank_chart.webp"
|
||||||
|
alt="Rank chart"
|
||||||
|
width={497}
|
||||||
|
height={100}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="md:hidden">
|
||||||
|
<h1>
|
||||||
|
<span className="text-3xl font-semibold text-zinc-400 sm:text-4xl">
|
||||||
|
$
|
||||||
|
</span>
|
||||||
|
<span className="text-3xl text-white sm:text-4xl">
|
||||||
|
{userData.net_worth.toLocaleString("en-US")}
|
||||||
|
</span>
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* User's Assets */}
|
||||||
|
<div className="col-span-7 flex flex-col rounded-2xl bg-zinc-800 bg-opacity-70">
|
||||||
|
{/* User's Assets Header */}
|
||||||
|
<div className="h-11 w-full rounded-t-2xl bg-pink-400">
|
||||||
|
<h1 className="m-1 text-center text-2xl font-bold">
|
||||||
|
Top Assets
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
{/* User's Assets Body */}
|
||||||
|
<div className="inline-grid grid-cols-2 items-center justify-start gap-2 p-5 sm:grid-cols-3 xl:grid-cols-4">
|
||||||
|
{errorCode === 20000 ? (
|
||||||
|
<h1 className=" text-zinc-400">{`Could not load assets`}</h1>
|
||||||
|
) : (
|
||||||
|
userData.assets.map(
|
||||||
|
(asset: {
|
||||||
|
name: string;
|
||||||
|
count: number;
|
||||||
|
provider: string;
|
||||||
|
}) => (
|
||||||
|
<div
|
||||||
|
className="flex items-center justify-center"
|
||||||
|
key={asset.name}
|
||||||
|
>
|
||||||
|
<div className="flex h-44 w-full max-w-[256px] flex-col items-center rounded-xl bg-zinc-900 bg-opacity-80 p-2">
|
||||||
|
<div className="mt-2 mb-2 h-24 w-24">
|
||||||
|
<div className="flex h-full w-full items-center justify-start p-2">
|
||||||
|
{
|
||||||
|
// if error code is 10000 or emote does not exist, show placeholder image
|
||||||
|
errorCode === 10000 ||
|
||||||
|
channelEmotes[asset.provider] === undefined ||
|
||||||
|
channelEmotes[asset.provider][asset.name] ===
|
||||||
|
undefined ? (
|
||||||
|
<h1 className="text-center text-zinc-400">{`404 :(`}</h1>
|
||||||
|
) : (
|
||||||
|
<Image
|
||||||
|
src={
|
||||||
|
channelEmotes[asset.provider][
|
||||||
|
asset.name
|
||||||
|
] ?? ""
|
||||||
|
}
|
||||||
|
alt={asset.name}
|
||||||
|
width={100}
|
||||||
|
height={100}
|
||||||
|
className="max-h-[100px]"
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
{/* Fix asset count to bottom right of image */}
|
||||||
|
<div className="relative rounded-full bg-zinc-900 bg-opacity-80 p-1">
|
||||||
|
<p
|
||||||
|
className="absolute -bottom-10 -right-2 -rotate-12 text-lg font-bold text-white"
|
||||||
|
style={{ textShadow: "0px 0px 4px black" }}
|
||||||
|
>
|
||||||
|
x{asset.count}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex w-full flex-row items-center justify-center">
|
||||||
|
{
|
||||||
|
// show provider logo (7tv, bttv, ffz, ttv)
|
||||||
|
asset.provider === "7tv" ? (
|
||||||
|
<div className="mr-1 pt-[1px] text-7tv ">
|
||||||
|
<SevenTVLogo />
|
||||||
|
</div>
|
||||||
|
) : asset.provider === "bttv" ? (
|
||||||
|
<div className="mr-1 pt-[1px] text-bttv">
|
||||||
|
<BTTVLogo />
|
||||||
|
</div>
|
||||||
|
) : asset.provider === "ffz" ? (
|
||||||
|
<div className="h-5 w-6 text-white">
|
||||||
|
<FFZLogo />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="mr-1 w-4 pt-[1px] text-ttv">
|
||||||
|
<TwitchLogo />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
<p className="text-md max-w-[80%] overflow-hidden overflow-ellipsis whitespace-nowrap font-bold text-white">
|
||||||
|
{asset.name}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* Sidebar */}
|
||||||
|
<div className="col-span-10 flex flex-col justify-start md:flex-row lg:col-span-3 lg:flex-col">
|
||||||
|
<div className="center mb-3 mr-3 inline-grid grid-cols-2 gap-3 rounded-2xl bg-zinc-800 bg-opacity-70 p-5 text-xl font-medium lg:mr-0">
|
||||||
|
{/* User's Stats, left side is label, right side is value */}
|
||||||
|
<h1>Points</h1>
|
||||||
|
<h1>{userData.points.toLocaleString("en-US")}</h1>
|
||||||
|
<h1>Shares</h1>
|
||||||
|
<h1>{userData.shares.toLocaleString("en-US")}</h1>
|
||||||
|
<h1>Trades</h1>
|
||||||
|
<h1>{(userData.trades ?? 0).toLocaleString("en-US")}</h1>
|
||||||
|
<h1>Peak rank</h1>
|
||||||
|
<h1>{(userData.peak_rank ?? 0).toLocaleString("en-US")}</h1>
|
||||||
|
<h1>Joined</h1>
|
||||||
|
<h1>
|
||||||
|
{new Date(userData.joined ?? 0).toLocaleDateString("en-US", {
|
||||||
|
year: "numeric",
|
||||||
|
month: "short",
|
||||||
|
})}
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
{/* User's Favorite Emote */}
|
||||||
|
<div className="flex flex-col rounded-2xl bg-zinc-800 bg-opacity-70">
|
||||||
|
<div className="h-11 w-full rounded-t-2xl bg-pink-400">
|
||||||
|
<h1 className="m-1 text-center text-2xl font-bold">
|
||||||
|
Favorite Emote
|
||||||
|
</h1>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="m-5 text-lg text-zinc-400">
|
||||||
|
This user has not yet set a favorite emote.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const SevenTVLogo = () => {
|
||||||
|
return (
|
||||||
|
<svg viewBox="0 0 109.6 80.9" width="1em">
|
||||||
|
<g>
|
||||||
|
<path
|
||||||
|
d="M84.1,22.2l5-8.7,2.7-4.6L86.8.2V0H60.1l5,8.7,5,8.7,2.8,4.8H84.1"
|
||||||
|
fill="currentColor"
|
||||||
|
></path>
|
||||||
|
<path
|
||||||
|
d="M29,80.6l5-8.7,5-8.7,5-8.7,5-8.7,5-8.7,5-8.7L62.7,22l-5-8.7-5-8.7L49.9.1H7.7l-5,8.7L0,13.4l5,8.7v.2h32l-5,8.7-5,8.7-5,8.7-5,8.7-5,8.7L8.5,72l5,8.7v.2H29"
|
||||||
|
fill="currentColor"
|
||||||
|
></path>
|
||||||
|
<path
|
||||||
|
d="M70.8,80.6H86.1l5-8.7,5-8.7,5-8.7,5-8.7,3.5-6-5-8.7v-.2H89.2l-5,8.7-5,8.7-.7,1.3-5-8.7-5-8.7-.7-1.3-5,8.7-5,8.7L55,53.1l5,8.7,5,8.7,5,8.7.8,1.4"
|
||||||
|
fill="currentColor"
|
||||||
|
></path>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const FFZLogo = () => {
|
||||||
|
return (
|
||||||
|
<svg viewBox="0 0 396 396">
|
||||||
|
<path
|
||||||
|
d="m150.06,151.58c-.77-6.33.31-12.45,1.99-18.5,2.37-8.51,9.11-14.22,15.62-18.44,8.71-5.65,18.98-8.6,30.02-8.89,7.26-.19,12.89,3.13,18.17,6.2,3.98,2.32,7.8,6.66,10.25,11.43,2.99,5.83,5.92,11.51,7.05,18.18,1.17,6.9,4.69,13.3,9.05,18.55,4.61,5.55,5.63,11.86,5.53,18.1-.15,8.77,3.32,16.07,6.61,23.64.93,2.14,2.15,3.87,4.76,3.08,2.58-.77,4.04-2.69,3.78-5.44-.32-3.41-.64-6.86-1.43-10.18-1.01-4.18-1.54-8.31-1.45-12.65.19-9.37,6.06-15.83,12.06-21.43,5.81-5.44,9.29-4.23,15.15,1.48,7.52,7.32,14.31,15.22,18.49,24.91,3.86,8.94,7.62,17.97,10.54,27.24,1.79,5.7,2.26,11.9,2.71,17.92.35,4.7-2.69,8.43-6.01,11.17-12.05,9.97-24.04,20.06-38.64,26.39-3.06,1.32-5.93,3.65-8.27,5.9-4.3,4.13-8.7,4.8-14.22,3.81-6.67-1.2-12.21,2.2-17.76,5.37-10.83,6.19-21.98,11.44-34.99,10.56-2.65-.18-5.35-.19-7.99.05-9.67.89-18.35-1.86-26.44-6.91-5.06-3.16-10.74-5.27-15.39-9.12-.62-.51-1.58-.75-1.96-1.37-3.61-5.84-8.03-5.41-13.72-2.82-7.66,3.48-8.07,3.02-13.2-3.77-3.48-4.6-8.91-6.59-13.27-10.01-11.43-8.97-22.52-18.11-29.39-31.42-2.17-4.21-2.9-8.38-2.59-12.82.76-10.87,1-21.85,7.82-31.3,6.01-8.32,10.79-17.68,19.29-23.9,5.9-4.32,10.15-2.9,14.27,3.26,6.93,10.36,7.99,21.4,4.42,33.03-1.46,4.76-.62,9.52-.8,14.28-.09,2.23,2.26,4.61,3.36,4.24,2.47-.83,5.83.99,7.52-2.37,5.96-11.87,14.26-22.67,17.36-35.82,1.65-7.02,2.21-14.34,1.72-21.63Z"
|
||||||
|
fill="currentColor"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const BTTVLogo = () => {
|
||||||
|
return (
|
||||||
|
<svg viewBox="0 0 300 300" height="1em">
|
||||||
|
<path
|
||||||
|
fill="transparent"
|
||||||
|
d="M249.771 150A99.771 99.922 0 0 1 150 249.922 99.771 99.922 0 0 1 50.229 150 99.771 99.922 0 0 1 150 50.078 99.771 99.922 0 0 1 249.771 150Z"
|
||||||
|
></path>
|
||||||
|
<path
|
||||||
|
fill="currentColor"
|
||||||
|
d="M150 1.74C68.409 1.74 1.74 68.41 1.74 150S68.41 298.26 150 298.26h148.26V150.17h-.004c0-.057.004-.113.004-.17C298.26 68.409 231.59 1.74 150 1.74zm0 49c55.11 0 99.26 44.15 99.26 99.26 0 55.11-44.15 99.26-99.26 99.26-55.11 0-99.26-44.15-99.26-99.26 0-55.11 44.15-99.26 99.26-99.26z"
|
||||||
|
></path>
|
||||||
|
<path
|
||||||
|
fill="currentColor"
|
||||||
|
d="M161.388 70.076c-10.662 0-19.42 7.866-19.42 17.67 0 9.803 8.758 17.67 19.42 17.67 10.662 0 19.42-7.867 19.42-17.67 0-9.804-8.758-17.67-19.42-17.67zm45.346 24.554-.02.022-.004.002c-5.402 2.771-11.53 6.895-18.224 11.978l-.002.002-.004.002c-25.943 19.766-60.027 54.218-80.344 80.33h-.072l-1.352 1.768c-5.114 6.69-9.267 12.762-12.098 18.006l-.082.082.022.021v.002l.004.002.174.176.052-.053.102.053-.07.072c30.826 30.537 81.213 30.431 111.918-.273 30.783-30.784 30.8-81.352.04-112.152l-.005-.004zM87.837 142.216c-9.803 0-17.67 8.758-17.67 19.42 0 10.662 7.867 19.42 17.67 19.42 9.804 0 17.67-8.758 17.67-19.42 0-10.662-7.866-19.42-17.67-19.42z"
|
||||||
|
></path>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const TwitchLogo = () => {
|
||||||
|
return (
|
||||||
|
<svg x="0px" y="0px" viewBox="0 0 2400 2800">
|
||||||
|
<g>
|
||||||
|
<polygon
|
||||||
|
className="fill-white"
|
||||||
|
points="2200,1300 1800,1700 1400,1700 1050,2050 1050,1700 600,1700 600,200 2200,200"
|
||||||
|
/>
|
||||||
|
<g>
|
||||||
|
<g id="Layer_1-2">
|
||||||
|
<path
|
||||||
|
fill="currentColor"
|
||||||
|
d="M500,0L0,500v1800h600v500l500-500h400l900-900V0H500z M2200,1300l-400,400h-400l-350,350v-350H600V200h1600 V1300z"
|
||||||
|
/>
|
||||||
|
<rect
|
||||||
|
x="1700"
|
||||||
|
y="550"
|
||||||
|
fill="currentColor"
|
||||||
|
width="200"
|
||||||
|
height="600"
|
||||||
|
/>
|
||||||
|
<rect
|
||||||
|
x="1150"
|
||||||
|
y="550"
|
||||||
|
fill="currentColor"
|
||||||
|
width="200"
|
||||||
|
height="600"
|
||||||
|
/>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
UserPage.getLayout = function getLayout(page: ReactElement) {
|
||||||
|
return <DashLayout>{page}</DashLayout>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default UserPage;
|
BIN
public/img/well_drawn_rank_chart.webp
Normal file
BIN
public/img/well_drawn_rank_chart.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
|
@ -13,6 +13,11 @@ module.exports = {
|
||||||
robotoMono: ["Roboto Mono", "monospace"],
|
robotoMono: ["Roboto Mono", "monospace"],
|
||||||
minecraft: ["Minecraft", "Roboto", "sans-serif"],
|
minecraft: ["Minecraft", "Roboto", "sans-serif"],
|
||||||
},
|
},
|
||||||
|
colors: {
|
||||||
|
"7tv": "#4fc2bc",
|
||||||
|
bttv: "#d50014",
|
||||||
|
ttv: "#9146FF",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: [],
|
plugins: [],
|
||||||
|
|
Loading…
Reference in a new issue