fix: fixing bottom panel scss

This commit is contained in:
Chubby Granny Chaser 2024-11-28 10:13:23 +00:00
parent f66bdd706b
commit f35c34fa63
No known key found for this signature in database
10 changed files with 78 additions and 152 deletions

View File

@ -1,23 +1,21 @@
import type { HowLongToBeatCategory } from "@types";
import { getHowLongToBeatGame, searchHowLongToBeat } from "@main/services";
import type { GameShop, HowLongToBeatCategory } from "@types";
import { HydraApi } from "@main/services";
import { registerEvent } from "../register-event";
import { formatName } from "@shared";
const getHowLongToBeat = async (
_event: Electron.IpcMainInvokeEvent,
title: string
shop: GameShop,
objectId: string
): Promise<HowLongToBeatCategory[] | null> => {
const response = await searchHowLongToBeat(title);
const game = response.data.find((game) => {
return formatName(game.game_name) === formatName(title);
const params = new URLSearchParams({
shop,
objectId: objectId.toString(),
});
if (!game) return null;
const howLongToBeat = await getHowLongToBeatGame(String(game.game_id));
return howLongToBeat;
return HydraApi.get(`/games/how-long-to-beat?${params.toString()}`, null, {
needsAuth: false,
});
};
registerEvent("getHowLongToBeat", getHowLongToBeat);

View File

@ -1,108 +0,0 @@
import axios from "axios";
import { requestWebPage } from "@main/helpers";
import type {
HowLongToBeatCategory,
HowLongToBeatSearchResponse,
} from "@types";
import { formatName } from "@shared";
import { logger } from "./logger";
import UserAgent from "user-agents";
const state = {
apiKey: null as string | null,
};
const getHowLongToBeatSearchApiKey = async () => {
const userAgent = new UserAgent();
const document = await requestWebPage("https://howlongtobeat.com/");
const scripts = Array.from(document.querySelectorAll("script"));
const appScript = scripts.find((script) =>
script.src.startsWith("/_next/static/chunks/pages/_app")
);
if (!appScript) return null;
const response = await axios.get(
`https://howlongtobeat.com${appScript.src}`,
{
headers: {
"User-Agent": userAgent.toString(),
},
}
);
const results = /fetch\("\/api\/search\/"\.concat\("(.*?)"\)/gm.exec(
response.data
);
if (!results) return null;
return results[1];
};
export const searchHowLongToBeat = async (gameName: string) => {
state.apiKey = state.apiKey ?? (await getHowLongToBeatSearchApiKey());
if (!state.apiKey) return { data: [] };
const userAgent = new UserAgent();
const response = await axios
.post(
`https://howlongtobeat.com/api/search/${state.apiKey}`,
{
searchType: "games",
searchTerms: formatName(gameName).split(" "),
searchPage: 1,
size: 20,
},
{
headers: {
"User-Agent": userAgent.toString(),
Referer: "https://howlongtobeat.com/",
},
}
)
.catch((error) => {
logger.error("Error searching HowLongToBeat:", error?.response?.status);
return { data: { data: [] } };
});
return response.data as HowLongToBeatSearchResponse;
};
const parseListItems = ($lis: Element[]) => {
return $lis.map(($li) => {
const title = $li.querySelector("h4")?.textContent;
const [, accuracyClassName] = Array.from(($li as HTMLElement).classList);
const accuracy = accuracyClassName.split("time_").at(1);
return {
title: title ?? "",
duration: $li.querySelector("h5")?.textContent ?? "",
accuracy: accuracy ?? "",
};
});
};
export const getHowLongToBeatGame = async (
id: string
): Promise<HowLongToBeatCategory[]> => {
const document = await requestWebPage(`https://howlongtobeat.com/game/${id}`);
const $ul = document.querySelector(".shadow_shadow ul");
if (!$ul) return [];
const $lis = Array.from($ul.children);
const [$firstLi] = $lis;
if ($firstLi.tagName === "DIV") {
const $pcData = $lis.find(($li) => $li.textContent?.includes("PC"));
return parseListItems(Array.from($pcData?.querySelectorAll("li") ?? []));
}
return parseListItems($lis);
};

View File

@ -4,7 +4,6 @@ export * from "./steam-250";
export * from "./steam-grid";
export * from "./window-manager";
export * from "./download";
export * from "./how-long-to-beat";
export * from "./process-watcher";
export * from "./main-loop";
export * from "./hydra-api";

View File

@ -55,8 +55,8 @@ contextBridge.exposeInMainWorld("electron", {
getGameShopDetails: (objectId: string, shop: GameShop, language: string) =>
ipcRenderer.invoke("getGameShopDetails", objectId, shop, language),
getRandomGame: () => ipcRenderer.invoke("getRandomGame"),
getHowLongToBeat: (title: string) =>
ipcRenderer.invoke("getHowLongToBeat", title),
getHowLongToBeat: (shop: GameShop, objectId: string) =>
ipcRenderer.invoke("getHowLongToBeat", shop, objectId),
getGames: (take?: number, skip?: number) =>
ipcRenderer.invoke("getGames", take, skip),
searchGameRepacks: (query: string) =>

View File

@ -6,8 +6,45 @@
<title>Hydra</title>
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src *; style-src 'self' 'unsafe-inline'; img-src 'self' data: local: *; media-src 'self' local: data: *; connect-src *; font-src *;"
content="default-src 'self'; script-src * 'unsafe-inline'; style-src 'self' 'unsafe-inline' https://do.featurebase.app/js/sdk.css; img-src 'self' data: local: *; media-src 'self' local: data: *; connect-src *; font-src *;"
/>
<script>
!(function (e, t) {
const a = "featurebase-sdk";
function n() {
if (!t.getElementById(a)) {
var e = t.createElement("script");
(e.id = a),
(e.src = "https://do.featurebase.app/js/sdk.js"),
t
.getElementsByTagName("script")[0]
.parentNode.insertBefore(
e,
t.getElementsByTagName("script")[0]
);
}
}
"function" != typeof e.Featurebase &&
(e.Featurebase = function () {
(e.Featurebase.q = e.Featurebase.q || []).push(arguments);
}),
"complete" === t.readyState || "interactive" === t.readyState
? n()
: t.addEventListener("DOMContentLoaded", n);
})(window, document);
</script>
<script>
Featurebase("initialize_feedback_widget", {
organization: "https://hydralauncher.featurebase.app", // Replace this with your organization name, copy-paste the subdomain part from your Featurebase workspace url (e.g. https://*yourorg*.featurebase.app)
theme: "light", // required
placement: "right", // optional - remove to hide the floating button
email: "youruser@example.com", // optional
defaultBoard: "yourboardname", // optional - preselect a board
locale: "en", // Change the language, view all available languages from https://help.featurebase.app/en/articles/8879098-using-featurebase-in-my-language
metadata: null, // Attach session-specific metadata to feedback. Refer to the advanced section for the details: https://help.featurebase.app/en/articles/3774671-advanced#7k8iriyap66
});
</script>
</head>
<body>
<div id="root"></div>

View File

@ -1,7 +1,7 @@
@use "../../scss/globals.scss";
.bottom-panel {
width: "100%";
width: 100%;
border-top: solid 1px globals.$border-color;
background-color: globals.$background-color;
padding: calc(globals.$spacing-unit / 2) calc(globals.$spacing-unit * 2);

View File

@ -66,7 +66,8 @@ declare global {
) => Promise<ShopDetails | null>;
getRandomGame: () => Promise<Steam250Game>;
getHowLongToBeat: (
title: string
shop: GameShop,
objectId: string
) => Promise<HowLongToBeatCategory[] | null>;
getGames: (take?: number, skip?: number) => Promise<CatalogueEntry[]>;
searchGameRepacks: (query: string) => Promise<GameRepack[]>;

View File

@ -97,8 +97,10 @@ export function Sidebar() {
});
} else {
try {
const howLongToBeat =
await window.electron.getHowLongToBeat(gameTitle);
const howLongToBeat = await window.electron.getHowLongToBeat(
shop,
objectId
);
if (howLongToBeat) {
howLongToBeatEntriesTable.add({

View File

@ -45,7 +45,8 @@ export function ProfileContent() {
return userProfile?.relation?.status === "ACCEPTED";
}, [userProfile]);
const buildUserGameDetailsPath = (game: UserGame) => {
const buildUserGameDetailsPath = useCallback(
(game: UserGame) => {
if (!userProfile?.hasActiveSubscription || game.achievementCount === 0) {
return buildGameDetailsPath({
...game,
@ -60,7 +61,9 @@ export function ProfileContent() {
: undefined;
return buildGameAchievementPath({ ...game }, userParams);
};
},
[userProfile]
);
const formatPlayTime = useCallback(
(playTimeInSeconds = 0) => {
@ -176,7 +179,7 @@ export function ProfileContent() {
game.achievementCount > 0 && (
<div
style={{
color: "white",
color: "#fff",
width: "100%",
display: "flex",
flexDirection: "column",
@ -232,6 +235,8 @@ export function ProfileContent() {
borderRadius: 4,
width: "100%",
height: "100%",
minWidth: "100%",
minHeight: "100%",
}}
/>
</button>
@ -259,6 +264,7 @@ export function ProfileContent() {
userStats,
numberFormatter,
t,
buildUserGameDetailsPath,
formatPlayTime,
navigate,
]);

View File

@ -3,12 +3,3 @@ export interface HowLongToBeatCategory {
duration: string;
accuracy: string;
}
export interface HowLongToBeatResult {
game_id: number;
game_name: string;
}
export interface HowLongToBeatSearchResponse {
data: HowLongToBeatResult[];
}