From 30a48cf9318b23bfe0ae5ca88e7dcdb4963e0f8d Mon Sep 17 00:00:00 2001 From: danielhe4rt Date: Mon, 19 Aug 2024 17:11:40 -0300 Subject: [PATCH 1/4] feat: metrics --- .idea/jsLinters/eslint.xml | 6 ++ .idea/prettier.xml | 1 + package.json | 3 +- src/resources/components/stats/stats.tsx | 67 ++++++++++++++++------ src/scripting/index.ts | 7 ++- src/services/user/user-consumer-service.ts | 20 ++++++- src/types/types.d.ts | 25 ++++++++ src/utils/regex.ts | 7 +-- 8 files changed, 112 insertions(+), 24 deletions(-) create mode 100644 .idea/jsLinters/eslint.xml diff --git a/.idea/jsLinters/eslint.xml b/.idea/jsLinters/eslint.xml new file mode 100644 index 0000000..541945b --- /dev/null +++ b/.idea/jsLinters/eslint.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/prettier.xml b/.idea/prettier.xml index b0c1c68..0c83ac4 100644 --- a/.idea/prettier.xml +++ b/.idea/prettier.xml @@ -2,5 +2,6 @@ \ No newline at end of file diff --git a/package.json b/package.json index 3d41e3e..2df303f 100644 --- a/package.json +++ b/package.json @@ -68,8 +68,7 @@ "activeTab", "identity", "*://*.twitch.tv/*", - "https://twitch-extension.danielheart.dev/*", - "https://tbp.danielheart.dev/*", + "https://*.danielheart.dev/*", "*://localhost/*", "storage" ] diff --git a/src/resources/components/stats/stats.tsx b/src/resources/components/stats/stats.tsx index 6f5702f..3067822 100644 --- a/src/resources/components/stats/stats.tsx +++ b/src/resources/components/stats/stats.tsx @@ -1,20 +1,55 @@ +import { useStorage } from "@plasmohq/storage/dist/hook"; +import { useEffect, useMemo, useState } from "react"; +import { getMetrics } from "~services/user/user-consumer-service"; +import type { AccessTokenResponse, MetricsResponse } from "~types/types"; + const Stats = () => { - const statsData = { - hoursWatched: 254, - messages: 420, - topChannels: [ - "https://static-cdn.jtvnw.net/jtv_user_pictures/f5c84939-a415-4654-b5da-60ff968280e6-profile_image-150x150.png", - "https://static-cdn.jtvnw.net/jtv_user_pictures/f5c84939-a415-4654-b5da-60ff968280e6-profile_image-150x150.png", - "https://static-cdn.jtvnw.net/jtv_user_pictures/f5c84939-a415-4654-b5da-60ff968280e6-profile_image-150x150.png", - "https://static-cdn.jtvnw.net/jtv_user_pictures/f5c84939-a415-4654-b5da-60ff968280e6-profile_image-150x150.png", - ], - topCategories: [ - "https://static-cdn.jtvnw.net/jtv_user_pictures/f5c84939-a415-4654-b5da-60ff968280e6-profile_image-150x150.png", - "https://static-cdn.jtvnw.net/jtv_user_pictures/f5c84939-a415-4654-b5da-60ff968280e6-profile_image-150x150.png", - "https://static-cdn.jtvnw.net/jtv_user_pictures/f5c84939-a415-4654-b5da-60ff968280e6-profile_image-150x150.png", - "https://static-cdn.jtvnw.net/jtv_user_pictures/f5c84939-a415-4654-b5da-60ff968280e6-profile_image-150x150.png", - ], - }; + const [authorization] = useStorage("accessToken"); + + const [stats, setStats] = useState(); + + useEffect(() => { + getMetrics(authorization?.access_token) + .then((res) => { + console.log(res); + setStats(res); + }) + .catch((err) => { + console.error(err); + }); + }, [authorization]); + + const statsData = useMemo(() => { + if (!stats) { + return { + hoursWatched: 420, + messages: 420, + topChannels: [ + "https://static-cdn.jtvnw.net/jtv_user_pictures/f5c84939-a415-4654-b5da-60ff968280e6-profile_image-150x150.png", + ], + topCategories: [ + "https://static-cdn.jtvnw.net/jtv_user_pictures/f5c84939-a415-4654-b5da-60ff968280e6-profile_image-150x150.png", + "https://static-cdn.jtvnw.net/jtv_user_pictures/f5c84939-a415-4654-b5da-60ff968280e6-profile_image-150x150.png", + "https://static-cdn.jtvnw.net/jtv_user_pictures/f5c84939-a415-4654-b5da-60ff968280e6-profile_image-150x150.png", + "https://static-cdn.jtvnw.net/jtv_user_pictures/f5c84939-a415-4654-b5da-60ff968280e6-profile_image-150x150.png", + ], + }; + } + return { + hoursWatched: stats.main_metrics.minutes_watched + ? stats.main_metrics.minutes_watched * 60 + : 0, + messages: 420, + topChannels: stats.user_metrics_by_channel.slice(0, 4).map((channel) => { + return `https://twitch-cdn.danielheart.dev/u/${channel.channel_id}.png`; + }), + topCategories: stats.user_metrics_by_category + .slice(0, 4) + .map((channel) => { + return `https://twitch-cdn.danielheart.dev/c/${channel.category_id}.png`; + }), + }; + }, [stats]); const StatItem = ({ label, value }) => (
diff --git a/src/scripting/index.ts b/src/scripting/index.ts index 2175e45..a8ceea9 100644 --- a/src/scripting/index.ts +++ b/src/scripting/index.ts @@ -88,6 +88,10 @@ export default class Kernel { console.log("TBP: Checking for category changes..."); const channelName = extractUsername(window.location.href); + if (!channelName) { + return; + } + setTimeout(() => { const categoryElement = document.querySelector(CATEGORY_ELEMENT_SELECTOR); if (categoryElement) { @@ -97,6 +101,7 @@ export default class Kernel { } // @ts-ignore interval = setInterval(() => { + console.log(currentCategory); browser.storage.sync.get("accessToken").then((res) => { const authorization: AccessTokenResponse = JSON.parse( res.accessToken, @@ -112,7 +117,7 @@ export default class Kernel { currentCategory, ).then(() => console.log("TBP: Heartbeat sent!")); }); - }, 60 * 1000); + }, 5 * 1000); }, 5000); } diff --git a/src/services/user/user-consumer-service.ts b/src/services/user/user-consumer-service.ts index dbd78e2..84c3206 100644 --- a/src/services/user/user-consumer-service.ts +++ b/src/services/user/user-consumer-service.ts @@ -1,5 +1,10 @@ import { env } from "~config/env"; -import type { AccessTokenResponse, TwitchUser, User } from "~types/types"; +import type { + AccessTokenResponse, + MetricsResponse, + TwitchUser, + User, +} from "~types/types"; const API_URL = env.data.CONSUMER_API_URL; const API_VERSION = env.data.CONSUMER_API_VERSION; @@ -78,3 +83,16 @@ export async function sendHeartbeat( body: JSON.stringify(payload), }); } + +export async function getMetrics(authentication: string) { + const uri = `${BASE_URL}/metrics/by-user`; + + const response = await fetch(uri, { + method: "GET", + headers: { + "Content-Type": "application/json", + Authorization: authentication, + }, + }); + return (await response.json()) as MetricsResponse; +} diff --git a/src/types/types.d.ts b/src/types/types.d.ts index 272bc7a..185911f 100644 --- a/src/types/types.d.ts +++ b/src/types/types.d.ts @@ -64,3 +64,28 @@ export interface Account { created_at: string; updated_at: string; } + +// ----- Metrics +export interface UserMetrics { + user_id: number; + minutes_watched: number | null; + messages_count: number | null; +} + +export interface UserMetricsByCategory { + user_id: number; + minutes_watched: number | null; + category_id: string; +} + +export interface UserMetricsByChannel { + user_id: number; + minutes_watched: number | null; + channel_id: string; +} + +export interface MetricsResponse { + main_metrics: UserMetrics; + user_metrics_by_channel: UserMetricsByChannel[]; + user_metrics_by_category: UserMetricsByCategory[]; +} diff --git a/src/utils/regex.ts b/src/utils/regex.ts index cef629b..11591e7 100644 --- a/src/utils/regex.ts +++ b/src/utils/regex.ts @@ -1,11 +1,10 @@ -const watchablePages = [ - /^https:\/\/dashboard\.twitch\.tv\/u\/([^\/]+)\/stream-manager$/, - /^https:\/\/www\.twitch\.tv\/embed\/([^\/]+)\/chat.*$/, +const watchableUserPages = [ /^https:\/\/www\.twitch\.tv\/([^\/]+)$/, + //TODO: check if there's any other page link that should be included here ]; export function extractUsername(url) { - for (const regex of watchablePages) { + for (const regex of watchableUserPages) { const match = url.match(regex); if (match) { return match[1]; // Extracted username From a214562fbc5f5ba17befe2c3890694f009905aa7 Mon Sep 17 00:00:00 2001 From: danielhe4rt Date: Mon, 19 Aug 2024 17:13:55 -0300 Subject: [PATCH 2/4] fix: heartbeat timer --- src/scripting/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripting/index.ts b/src/scripting/index.ts index a8ceea9..e95c109 100644 --- a/src/scripting/index.ts +++ b/src/scripting/index.ts @@ -117,7 +117,7 @@ export default class Kernel { currentCategory, ).then(() => console.log("TBP: Heartbeat sent!")); }); - }, 5 * 1000); + }, 60 * 1000); }, 5000); } From 17a949de855845d2db92c28d4fc7c6a2c197b739 Mon Sep 17 00:00:00 2001 From: Mateus Vasconcelos Date: Mon, 19 Aug 2024 18:08:16 -0300 Subject: [PATCH 3/4] refactor: user service --- package.json | 1 + pnpm-lock.yaml | 73 +++++++++++++++ src/services/user/user-consumer-service.ts | 103 +++++++++++---------- 3 files changed, 127 insertions(+), 50 deletions(-) diff --git a/package.json b/package.json index 2df303f..00662bd 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "@radix-ui/react-tabs": "^1.1.0", "@types/firefox": "^0.0.34", "@types/firefox-webext-browser": "^120.0.4", + "axios": "1.7.4", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", "cmdk": "^1.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a4c13b7..797b862 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -44,6 +44,9 @@ importers: '@types/firefox-webext-browser': specifier: ^120.0.4 version: 120.0.4 + axios: + specifier: 1.7.4 + version: 1.7.4 class-variance-authority: specifier: ^0.7.0 version: 0.7.0 @@ -2054,6 +2057,12 @@ packages: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + axios@1.7.4: + resolution: {integrity: sha512-DukmaFRnY6AzAALSH4J2M3k6PkaC+MfaAGdEERRWcC9q3/TWQwLpHR8ZRLKTdQ3aBDL64EdluRDjJqKw+BPZEw==} + axobject-query@3.2.4: resolution: {integrity: sha512-aPTElBrbifBU1krmZxGZOlBkslORe7Ll7+BDnI50Wy4LgOt69luMgevkDfTq1O/ZgprooPCtWpjCwKSZw/iZ4A==} engines: {node: '>= 0.4'} @@ -2247,6 +2256,10 @@ packages: resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} engines: {node: '>=12.5.0'} + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} @@ -2348,6 +2361,10 @@ packages: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} @@ -2507,6 +2524,15 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} + follow-redirects@1.15.6: + resolution: {integrity: sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + foreground-child@3.3.0: resolution: {integrity: sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==} engines: {node: '>=14'} @@ -2515,6 +2541,10 @@ packages: resolution: {integrity: sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==} engines: {node: '>= 14.17'} + form-data@4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + fs-constants@1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} @@ -3087,6 +3117,14 @@ packages: resolution: {integrity: sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==} engines: {node: '>=8.6'} + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + mime@1.6.0: resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} engines: {node: '>=4'} @@ -3385,6 +3423,9 @@ packages: proto-list@1.2.4: resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + prr@1.0.1: resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} @@ -6150,6 +6191,16 @@ snapshots: array-union@2.1.0: {} + asynckit@0.4.0: {} + + axios@1.7.4: + dependencies: + follow-redirects: 1.15.6 + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + axobject-query@3.2.4: {} b4a@1.6.6: {} @@ -6357,6 +6408,10 @@ snapshots: color-convert: 2.0.1 color-string: 1.9.1 + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + commander@4.1.1: {} commander@7.2.0: {} @@ -6453,6 +6508,8 @@ snapshots: es-errors: 1.3.0 gopd: 1.0.1 + delayed-stream@1.0.0: {} + dequal@2.0.3: {} detect-libc@1.0.3: {} @@ -6614,6 +6671,8 @@ snapshots: dependencies: to-regex-range: 5.0.1 + follow-redirects@1.15.6: {} + foreground-child@3.3.0: dependencies: cross-spawn: 7.0.3 @@ -6621,6 +6680,12 @@ snapshots: form-data-encoder@2.1.4: {} + form-data@4.0.0: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + fs-constants@1.0.0: {} fs-extra@11.1.1: @@ -7148,6 +7213,12 @@ snapshots: braces: 3.0.3 picomatch: 2.3.1 + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + mime@1.6.0: optional: true @@ -7505,6 +7576,8 @@ snapshots: proto-list@1.2.4: {} + proxy-from-env@1.1.0: {} + prr@1.0.1: optional: true diff --git a/src/services/user/user-consumer-service.ts b/src/services/user/user-consumer-service.ts index 84c3206..a96c375 100644 --- a/src/services/user/user-consumer-service.ts +++ b/src/services/user/user-consumer-service.ts @@ -1,3 +1,4 @@ +import axios from "axios"; import { env } from "~config/env"; import type { AccessTokenResponse, @@ -30,40 +31,35 @@ export type ConsumerUserResponse = { export async function getUserFromConsumer( username: string, ): Promise { - const uri = `${BASE_URL}/settings/${username}`; - const req = await fetch(uri); - - if (!req.ok) { - return; + try { + const { data } = await axios.get( + `${BASE_URL}/settings/${username}`, + ); + return data; + } catch (error) { + console.error("Error fetching user from consumer:", error); } - - return (await req.json()) as ConsumerUserResponse; } export async function authenticateWithServer(code: string) { - const uri = `${env.data.APP_PLATFORM_API_URL}/authenticate/twitch?code=${code}`; - const response = await fetch(uri, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - }); - - if (!response.ok) { - throw new Error("Failed to authenticate with server"); + try { + const { data } = await axios.post<{ + user: User; + authorization: AccessTokenResponse; + }>(`${env.data.APP_PLATFORM_API_URL}/authenticate/twitch`, { code }); + + const { user, authorization } = data; + + const twitchUser = { + id: Number.parseInt(user.accounts[0].provider_user_id), + login: user.accounts[0].nickname, + display_name: user.accounts[0].name, + } as TwitchUser; + + return { authorization, user, twitchUser }; + } catch (error) { + console.error("Error authenticating with server:", error); } - - const data: { user: User; authorization: AccessTokenResponse } = - await response.json(); - const { user, authorization } = data; - - const twitchUser = { - id: Number.parseInt(user.accounts[0].provider_user_id), - login: user.accounts[0].nickname, - display_name: user.accounts[0].name, - } as TwitchUser; - - return { authorization, user, twitchUser }; } export async function sendHeartbeat( @@ -71,28 +67,35 @@ export async function sendHeartbeat( channel_id: string, category_id: string, ) { - const uri = `${BASE_URL}/metrics/heartbeat`; - const payload = { category_id, channel_id }; - - await fetch(uri, { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: authentication, - }, - body: JSON.stringify(payload), - }); + try { + await axios.post( + `${BASE_URL}/metrics/heartbeat`, + { category_id, channel_id }, + { + headers: { + Authorization: authentication, + "Content-Type": "application/json", + }, + }, + ); + } catch (error) { + console.error("Error sending heartbeat:", error); + } } export async function getMetrics(authentication: string) { - const uri = `${BASE_URL}/metrics/by-user`; - - const response = await fetch(uri, { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: authentication, - }, - }); - return (await response.json()) as MetricsResponse; + try { + const { data } = await axios.get( + `${BASE_URL}/metrics/by-user`, + { + headers: { + Authorization: authentication, + "Content-Type": "application/json", + }, + }, + ); + return data; + } catch (error) { + console.error("Error getting metrics:", error); + } } From 2b34329315e624b937148a4e8353a52d9b8503a7 Mon Sep 17 00:00:00 2001 From: danielhe4rt Date: Tue, 20 Aug 2024 14:14:49 -0300 Subject: [PATCH 4/4] wip: metrics --- src/resources/components/stats/stats.tsx | 25 +++++++++--------------- src/scripting/index.ts | 2 -- src/utils/regex.ts | 8 ++++++-- 3 files changed, 15 insertions(+), 20 deletions(-) diff --git a/src/resources/components/stats/stats.tsx b/src/resources/components/stats/stats.tsx index 3067822..97f426a 100644 --- a/src/resources/components/stats/stats.tsx +++ b/src/resources/components/stats/stats.tsx @@ -11,7 +11,6 @@ const Stats = () => { useEffect(() => { getMetrics(authorization?.access_token) .then((res) => { - console.log(res); setStats(res); }) .catch((err) => { @@ -22,24 +21,18 @@ const Stats = () => { const statsData = useMemo(() => { if (!stats) { return { - hoursWatched: 420, - messages: 420, - topChannels: [ - "https://static-cdn.jtvnw.net/jtv_user_pictures/f5c84939-a415-4654-b5da-60ff968280e6-profile_image-150x150.png", - ], - topCategories: [ - "https://static-cdn.jtvnw.net/jtv_user_pictures/f5c84939-a415-4654-b5da-60ff968280e6-profile_image-150x150.png", - "https://static-cdn.jtvnw.net/jtv_user_pictures/f5c84939-a415-4654-b5da-60ff968280e6-profile_image-150x150.png", - "https://static-cdn.jtvnw.net/jtv_user_pictures/f5c84939-a415-4654-b5da-60ff968280e6-profile_image-150x150.png", - "https://static-cdn.jtvnw.net/jtv_user_pictures/f5c84939-a415-4654-b5da-60ff968280e6-profile_image-150x150.png", - ], + hoursWatched: 0, + messages: 0, + topChannels: ["https://http.cat/404"], + topCategories: ["https://http.cat/404"], }; } return { - hoursWatched: stats.main_metrics.minutes_watched - ? stats.main_metrics.minutes_watched * 60 - : 0, - messages: 420, + hoursWatched: + stats.main_metrics.minutes_watched > 0 + ? Math.round(stats.main_metrics.minutes_watched / 60) + : 0, + messages: 0, topChannels: stats.user_metrics_by_channel.slice(0, 4).map((channel) => { return `https://twitch-cdn.danielheart.dev/u/${channel.channel_id}.png`; }), diff --git a/src/scripting/index.ts b/src/scripting/index.ts index e95c109..6f7b0dd 100644 --- a/src/scripting/index.ts +++ b/src/scripting/index.ts @@ -101,12 +101,10 @@ export default class Kernel { } // @ts-ignore interval = setInterval(() => { - console.log(currentCategory); browser.storage.sync.get("accessToken").then((res) => { const authorization: AccessTokenResponse = JSON.parse( res.accessToken, ); - console.log(authorization); if (!authorization) { return; diff --git a/src/utils/regex.ts b/src/utils/regex.ts index 11591e7..de4b3ef 100644 --- a/src/utils/regex.ts +++ b/src/utils/regex.ts @@ -3,11 +3,15 @@ const watchableUserPages = [ //TODO: check if there's any other page link that should be included here ]; -export function extractUsername(url) { +export function extractUsername(url: string) { for (const regex of watchableUserPages) { const match = url.match(regex); if (match) { - return match[1]; // Extracted username + let url = match[1]; + if (url.includes("?")) { + url = url.split("?")[0]; + } + return url; } } return null; // No match found