mirror of
https://github.com/hydralauncher/hydra.git
synced 2025-02-03 08:43:48 +03:00
Merge pull request #92 from zamitto/feat/enhance-get-random-game
Feat/enhance get random game
This commit is contained in:
commit
cbfc822d73
@ -1,27 +1,40 @@
|
|||||||
import shuffle from "lodash/shuffle";
|
import shuffle from "lodash/shuffle";
|
||||||
|
|
||||||
import { getRandomSteam250List } from "@main/services";
|
import { Steam250Game, getSteam250List } from "@main/services";
|
||||||
|
|
||||||
import { registerEvent } from "../register-event";
|
import { registerEvent } from "../register-event";
|
||||||
import { searchGames, searchRepacks } from "../helpers/search-games";
|
import { searchGames, searchRepacks } from "../helpers/search-games";
|
||||||
import { formatName } from "@main/helpers";
|
|
||||||
|
const state = { games: Array<Steam250Game>(), index: 0 };
|
||||||
|
|
||||||
const getRandomGame = async (_event: Electron.IpcMainInvokeEvent) => {
|
const getRandomGame = async (_event: Electron.IpcMainInvokeEvent) => {
|
||||||
return getRandomSteam250List().then(async (games) => {
|
if (state.games.length == 0) {
|
||||||
const shuffledList = shuffle(games);
|
const steam250List = await getSteam250List();
|
||||||
|
|
||||||
for (const game of shuffledList) {
|
const filteredSteam250List = steam250List.filter((game) => {
|
||||||
const repacks = searchRepacks(formatName(game.title));
|
const repacks = searchRepacks(game.title);
|
||||||
|
const catalogue = searchGames({ query: game.title });
|
||||||
|
|
||||||
if (repacks.length) {
|
return repacks.length && catalogue.length;
|
||||||
const results = await searchGames({ query: game.title });
|
});
|
||||||
|
|
||||||
if (results.length) {
|
state.games = shuffle(filteredSteam250List);
|
||||||
return results[0].objectID;
|
}
|
||||||
}
|
|
||||||
}
|
if (state.games.length == 0) {
|
||||||
}
|
return "";
|
||||||
});
|
}
|
||||||
|
|
||||||
|
const resultObjectId = state.games[state.index].objectID;
|
||||||
|
|
||||||
|
state.index += 1;
|
||||||
|
|
||||||
|
if (state.index == state.games.length) {
|
||||||
|
state.index = 0;
|
||||||
|
state.games = shuffle(state.games);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultObjectId;
|
||||||
};
|
};
|
||||||
|
|
||||||
registerEvent(getRandomGame, {
|
registerEvent(getRandomGame, {
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
import { registerEvent } from "../register-event";
|
import { registerEvent } from "../register-event";
|
||||||
import { searchGames } from "../helpers/search-games";
|
import { searchGames } from "../helpers/search-games";
|
||||||
|
import { CatalogueEntry } from "@types";
|
||||||
|
|
||||||
registerEvent(
|
const searchGamesEvent = async (
|
||||||
(_event: Electron.IpcMainInvokeEvent, query: string) =>
|
_event: Electron.IpcMainInvokeEvent,
|
||||||
searchGames({ query, take: 12 }),
|
query: string
|
||||||
{
|
): Promise<CatalogueEntry[]> => {
|
||||||
name: "searchGames",
|
return searchGames({ query, take: 12 });
|
||||||
memoize: true,
|
};
|
||||||
}
|
|
||||||
);
|
registerEvent(searchGamesEvent, {
|
||||||
|
name: "searchGames",
|
||||||
|
memoize: true,
|
||||||
|
});
|
||||||
|
@ -42,11 +42,11 @@ export interface SearchGamesArgs {
|
|||||||
skip?: number;
|
skip?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const searchGames = async ({
|
export const searchGames = ({
|
||||||
query,
|
query,
|
||||||
take,
|
take,
|
||||||
skip,
|
skip,
|
||||||
}: SearchGamesArgs): Promise<CatalogueEntry[]> => {
|
}: SearchGamesArgs): CatalogueEntry[] => {
|
||||||
const results = steamGamesIndex
|
const results = steamGamesIndex
|
||||||
.search(formatName(query || ""), { limit: take, offset: skip })
|
.search(formatName(query || ""), { limit: take, offset: skip })
|
||||||
.map((index) => {
|
.map((index) => {
|
||||||
@ -61,11 +61,9 @@ export const searchGames = async ({
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
return Promise.all(results).then((resultsWithRepacks) =>
|
return orderBy(
|
||||||
orderBy(
|
results,
|
||||||
resultsWithRepacks,
|
[({ repacks }) => repacks.length, "repacks"],
|
||||||
[({ repacks }) => repacks.length, "repacks"],
|
["desc"]
|
||||||
["desc"]
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,24 +1,31 @@
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { JSDOM } from "jsdom";
|
import { JSDOM } from "jsdom";
|
||||||
import shuffle from "lodash/shuffle";
|
|
||||||
|
export interface Steam250Game {
|
||||||
|
title: string;
|
||||||
|
objectID: string;
|
||||||
|
}
|
||||||
|
|
||||||
export const requestSteam250 = async (path: string) => {
|
export const requestSteam250 = async (path: string) => {
|
||||||
return axios.get(`https://steam250.com${path}`).then((response) => {
|
return axios
|
||||||
const { window } = new JSDOM(response.data);
|
.get(`https://steam250.com${path}`)
|
||||||
const { document } = window;
|
.then((response) => {
|
||||||
|
const { window } = new JSDOM(response.data);
|
||||||
|
const { document } = window;
|
||||||
|
|
||||||
return Array.from(document.querySelectorAll(".appline .title a")).map(
|
return Array.from(document.querySelectorAll(".appline .title a"))
|
||||||
($title: HTMLAnchorElement) => {
|
.map(($title: HTMLAnchorElement) => {
|
||||||
const steamGameUrl = $title.href;
|
const steamGameUrl = $title.href;
|
||||||
if (!steamGameUrl) return null;
|
if (!steamGameUrl) return null;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
title: $title.textContent,
|
title: $title.textContent,
|
||||||
objectID: steamGameUrl.split("/").pop(),
|
objectID: steamGameUrl.split("/").pop(),
|
||||||
};
|
} as Steam250Game;
|
||||||
}
|
})
|
||||||
);
|
.filter((game) => game != null);
|
||||||
});
|
})
|
||||||
|
.catch((_) => [] as Steam250Game[]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const steam250Paths = [
|
const steam250Paths = [
|
||||||
@ -28,7 +35,15 @@ const steam250Paths = [
|
|||||||
"/most_played",
|
"/most_played",
|
||||||
];
|
];
|
||||||
|
|
||||||
export const getRandomSteam250List = async () => {
|
export const getSteam250List = async () => {
|
||||||
const [path] = shuffle(steam250Paths);
|
const gamesList = (
|
||||||
return requestSteam250(path);
|
await Promise.all(steam250Paths.map((path) => requestSteam250(path)))
|
||||||
|
).flat();
|
||||||
|
|
||||||
|
const gamesMap: Map<string, Steam250Game> = gamesList.reduce((map, item) => {
|
||||||
|
map.set(item.objectID, item);
|
||||||
|
return map;
|
||||||
|
}, new Map());
|
||||||
|
|
||||||
|
return [...gamesMap.values()];
|
||||||
};
|
};
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import Color from "color";
|
import Color from "color";
|
||||||
import { average } from "color.js";
|
import { average } from "color.js";
|
||||||
import { useCallback, useEffect, useRef, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
import { useNavigate, useParams, useSearchParams } from "react-router-dom";
|
import { useNavigate, useParams, useSearchParams } from "react-router-dom";
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
@ -33,6 +33,7 @@ export function GameDetails() {
|
|||||||
const { objectID, shop } = useParams();
|
const { objectID, shop } = useParams();
|
||||||
|
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
const [isLoadingRandomGame, setIsLoadingRandomGame] = useState(false);
|
||||||
const [color, setColor] = useState("");
|
const [color, setColor] = useState("");
|
||||||
const [gameDetails, setGameDetails] = useState<ShopDetails | null>(null);
|
const [gameDetails, setGameDetails] = useState<ShopDetails | null>(null);
|
||||||
const [howLongToBeat, setHowLongToBeat] = useState<{
|
const [howLongToBeat, setHowLongToBeat] = useState<{
|
||||||
@ -53,18 +54,10 @@ export function GameDetails() {
|
|||||||
const [showRepacksModal, setShowRepacksModal] = useState(false);
|
const [showRepacksModal, setShowRepacksModal] = useState(false);
|
||||||
const [showSelectFolderModal, setShowSelectFolderModal] = useState(false);
|
const [showSelectFolderModal, setShowSelectFolderModal] = useState(false);
|
||||||
|
|
||||||
const randomGameObjectID = useRef<string | null>(null);
|
|
||||||
|
|
||||||
const dispatch = useAppDispatch();
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
const { game: gameDownloading, startDownload, isDownloading } = useDownload();
|
const { game: gameDownloading, startDownload, isDownloading } = useDownload();
|
||||||
|
|
||||||
const getRandomGame = useCallback(() => {
|
|
||||||
window.electron.getRandomGame().then((objectID) => {
|
|
||||||
randomGameObjectID.current = objectID;
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleImageSettled = useCallback((url: string) => {
|
const handleImageSettled = useCallback((url: string) => {
|
||||||
average(url, { amount: 1, format: "hex" })
|
average(url, { amount: 1, format: "hex" })
|
||||||
.then((color) => {
|
.then((color) => {
|
||||||
@ -89,8 +82,6 @@ export function GameDetails() {
|
|||||||
setIsGamePlaying(false);
|
setIsGamePlaying(false);
|
||||||
dispatch(setHeaderTitle(""));
|
dispatch(setHeaderTitle(""));
|
||||||
|
|
||||||
getRandomGame();
|
|
||||||
|
|
||||||
window.electron
|
window.electron
|
||||||
.getGameShopDetails(objectID, "steam", getSteamLanguage(i18n.language))
|
.getGameShopDetails(objectID, "steam", getSteamLanguage(i18n.language))
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
@ -107,6 +98,7 @@ export function GameDetails() {
|
|||||||
|
|
||||||
setGameDetails(result);
|
setGameDetails(result);
|
||||||
dispatch(setHeaderTitle(result.name));
|
dispatch(setHeaderTitle(result.name));
|
||||||
|
setIsLoadingRandomGame(false);
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
@ -114,7 +106,7 @@ export function GameDetails() {
|
|||||||
|
|
||||||
getGame();
|
getGame();
|
||||||
setHowLongToBeat({ isLoading: true, data: null });
|
setHowLongToBeat({ isLoading: true, data: null });
|
||||||
}, [getGame, getRandomGame, dispatch, navigate, objectID, i18n.language]);
|
}, [getGame, dispatch, navigate, objectID, i18n.language]);
|
||||||
|
|
||||||
const isGameDownloading = isDownloading && gameDownloading?.id === game?.id;
|
const isGameDownloading = isDownloading && gameDownloading?.id === game?.id;
|
||||||
|
|
||||||
@ -158,16 +150,15 @@ export function GameDetails() {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleRandomizerClick = () => {
|
const handleRandomizerClick = async () => {
|
||||||
if (!randomGameObjectID.current) return;
|
setIsLoadingRandomGame(true);
|
||||||
|
const randomGameObjectID = await window.electron.getRandomGame();
|
||||||
|
|
||||||
const searchParams = new URLSearchParams({
|
const searchParams = new URLSearchParams({
|
||||||
fromRandomizer: "1",
|
fromRandomizer: "1",
|
||||||
});
|
});
|
||||||
|
|
||||||
navigate(
|
navigate(`/game/steam/${randomGameObjectID}?${searchParams.toString()}`);
|
||||||
`/game/steam/${randomGameObjectID.current}?${searchParams.toString()}`
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const fromRandomizer = searchParams.get("fromRandomizer");
|
const fromRandomizer = searchParams.get("fromRandomizer");
|
||||||
@ -281,6 +272,7 @@ export function GameDetails() {
|
|||||||
className={styles.randomizerButton}
|
className={styles.randomizerButton}
|
||||||
onClick={handleRandomizerClick}
|
onClick={handleRandomizerClick}
|
||||||
theme="outline"
|
theme="outline"
|
||||||
|
disabled={isLoadingRandomGame}
|
||||||
>
|
>
|
||||||
<div style={{ width: 16, height: 16, position: "relative" }}>
|
<div style={{ width: 16, height: 16, position: "relative" }}>
|
||||||
<Lottie
|
<Lottie
|
||||||
|
@ -58,14 +58,12 @@ export function Home() {
|
|||||||
const getRandomGame = useCallback(() => {
|
const getRandomGame = useCallback(() => {
|
||||||
setIsLoadingRandomGame(true);
|
setIsLoadingRandomGame(true);
|
||||||
|
|
||||||
window.electron
|
window.electron.getRandomGame().then((objectID) => {
|
||||||
.getRandomGame()
|
if (objectID) {
|
||||||
.then((objectID) => {
|
|
||||||
randomGameObjectID.current = objectID;
|
randomGameObjectID.current = objectID;
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
setIsLoadingRandomGame(false);
|
setIsLoadingRandomGame(false);
|
||||||
});
|
}
|
||||||
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const handleRandomizerClick = () => {
|
const handleRandomizerClick = () => {
|
||||||
|
Loading…
Reference in New Issue
Block a user