Compare commits

...

10 Commits

Author SHA1 Message Date
Moyasee
92d87c5d33 refactor: remove unnecessary useEffect in LibraryGameCard 2025-12-31 01:59:25 +02:00
Moyasee
af884d3772 refactor: simplify cover image assignment in LibraryGameCard 2025-12-30 14:09:04 +02:00
Moyasee
dc31ac0831 fix: library cards not using placeholder and icon as a game cover 2025-12-30 00:25:45 +02:00
Chubby Granny Chaser
9769eecec6 Merge pull request #1907 from hydralauncher/fix/lint-buzz
Some checks failed
Build / build (ubuntu-latest) (push) Has been cancelled
Build / build (windows-2022) (push) Has been cancelled
refactor: improve code formatting and consistency in DownloadManager
2025-12-27 00:56:29 +00:00
Moyasee
91adb97013 refactor: improve code formatting and consistency in DownloadManager 2025-12-27 02:50:27 +02:00
Chubby Granny Chaser
f138b2efcb Merge pull request #1906 from Wkeynhk/main
Buzzheavier fix
2025-12-27 00:47:44 +00:00
Wkeynhk
991aa05760 Sonar fix2 2025-12-27 03:23:36 +03:00
Wkeynhk
aff9e13bca Sonar fix 2025-12-27 03:17:42 +03:00
Wkeynhk
240a75c1d0 Buzzheavier fix 2025-12-27 03:02:35 +03:00
Chubby Granny Chaser
edbe86a1fb Merge pull request #1904 from hydralauncher/feat/LBX-155
Some checks failed
Build / build (ubuntu-latest) (push) Has been cancelled
Build / build (windows-2022) (push) Has been cancelled
fix: notification item styling
2025-12-26 22:54:13 +00:00
3 changed files with 66 additions and 24 deletions

View File

@@ -35,18 +35,27 @@ export class DownloadManager {
): string | undefined { ): string | undefined {
if (originalUrl?.includes("#")) { if (originalUrl?.includes("#")) {
const hashPart = originalUrl.split("#")[1]; const hashPart = originalUrl.split("#")[1];
if (hashPart && !hashPart.startsWith("http")) return hashPart; if (hashPart && !hashPart.startsWith("http") && hashPart.includes(".")) {
return hashPart;
}
} }
if (url.includes("#")) { if (url.includes("#")) {
const hashPart = url.split("#")[1]; const hashPart = url.split("#")[1];
if (hashPart && !hashPart.startsWith("http")) return hashPart; if (hashPart && !hashPart.startsWith("http") && hashPart.includes(".")) {
return hashPart;
}
} }
try { try {
const urlObj = new URL(url); const urlObj = new URL(url);
const filename = urlObj.pathname.split("/").pop(); const pathname = urlObj.pathname;
if (filename?.length) return filename; const pathParts = pathname.split("/");
const filename = pathParts[pathParts.length - 1];
if (filename?.includes(".") && filename.length > 0) {
return decodeURIComponent(filename);
}
} catch { } catch {
// Invalid URL // Invalid URL
} }
@@ -55,7 +64,7 @@ export class DownloadManager {
} }
private static sanitizeFilename(filename: string): string { private static sanitizeFilename(filename: string): string {
return filename.replace(/[<>:"/\\|?*]/g, "_"); return filename.replaceAll(/[<>:"/\\|?*]/g, "_");
} }
private static createDownloadPayload( private static createDownloadPayload(
@@ -64,13 +73,19 @@ export class DownloadManager {
downloadId: string, downloadId: string,
savePath: string savePath: string
) { ) {
const filename = this.extractFilename(directUrl, originalUrl); const filename =
this.extractFilename(originalUrl, directUrl) ||
this.extractFilename(directUrl);
const sanitizedFilename = filename const sanitizedFilename = filename
? this.sanitizeFilename(filename) ? this.sanitizeFilename(filename)
: undefined; : undefined;
if (sanitizedFilename) { if (sanitizedFilename) {
logger.log(`[DownloadManager] Using filename: ${sanitizedFilename}`); logger.log(`[DownloadManager] Using filename: ${sanitizedFilename}`);
} else {
logger.log(
`[DownloadManager] No filename extracted, aria2 will use default`
);
} }
return { return {
@@ -227,10 +242,10 @@ export class DownloadManager {
) )
) { ) {
gameFilesManager.extractDownloadedFile(); gameFilesManager.extractDownloadedFile();
} else { } else if (download.folderName) {
gameFilesManager gameFilesManager
.extractFilesInDirectory( .extractFilesInDirectory(
path.join(download.downloadPath, download.folderName!) path.join(download.downloadPath, download.folderName)
) )
.then(() => gameFilesManager.setExtractionComplete()); .then(() => gameFilesManager.setExtractionComplete());
} }

View File

@@ -221,6 +221,26 @@
left: 0; left: 0;
z-index: 0; z-index: 0;
} }
&__cover-placeholder {
position: relative;
width: 100%;
height: 100%;
min-width: 100%;
min-height: 100%;
background: linear-gradient(
90deg,
rgba(255, 255, 255, 0.08) 0%,
rgba(255, 255, 255, 0.04) 50%,
rgba(255, 255, 255, 0.08) 100%
);
border-radius: 4px;
color: rgba(255, 255, 255, 0.3);
display: flex;
align-items: center;
justify-content: center;
z-index: 0;
}
} }
@keyframes pulse { @keyframes pulse {

View File

@@ -1,7 +1,12 @@
import { LibraryGame } from "@types"; import { LibraryGame } from "@types";
import { useGameCard } from "@renderer/hooks"; import { useGameCard } from "@renderer/hooks";
import { memo } from "react"; import { memo, useState } from "react";
import { ClockIcon, AlertFillIcon, TrophyIcon } from "@primer/octicons-react"; import {
ClockIcon,
AlertFillIcon,
TrophyIcon,
ImageIcon,
} from "@primer/octicons-react";
import "./library-game-card.scss"; import "./library-game-card.scss";
interface LibraryGameCardProps { interface LibraryGameCardProps {
@@ -25,14 +30,9 @@ export const LibraryGameCard = memo(function LibraryGameCard({
const { formatPlayTime, handleCardClick, handleContextMenuClick } = const { formatPlayTime, handleCardClick, handleContextMenuClick } =
useGameCard(game, onContextMenu); useGameCard(game, onContextMenu);
const coverImage = ( const coverImage = game.coverImageUrl?.replaceAll("\\", "/") ?? "";
game.customIconUrl ??
game.coverImageUrl ?? const [imageError, setImageError] = useState(false);
game.libraryImageUrl ??
game.libraryHeroImageUrl ??
game.iconUrl ??
""
).replaceAll("\\", "/");
return ( return (
<button <button
@@ -98,12 +98,19 @@ export const LibraryGameCard = memo(function LibraryGameCard({
)} )}
</div> </div>
<img {imageError || !coverImage ? (
src={coverImage ?? undefined} <div className="library-game-card__cover-placeholder">
alt={game.title} <ImageIcon size={48} />
className="library-game-card__game-image" </div>
loading="lazy" ) : (
/> <img
src={coverImage}
alt={game.title}
className="library-game-card__game-image"
loading="lazy"
onError={() => setImageError(true)}
/>
)}
</button> </button>
); );
}); });