mirror of
https://github.com/hydralauncher/hydra.git
synced 2026-01-18 16:53:57 +00:00
ci: deleting comments
This commit is contained in:
@@ -8,15 +8,12 @@ import { gameAchievementsSublevel, levelKeys, db } from "@main/level";
|
||||
import { logger } from "@main/services/logger";
|
||||
import type { GameShop, User } from "@types";
|
||||
|
||||
/**
|
||||
* Uploads an achievement image to CDN using presigned URL
|
||||
*/
|
||||
|
||||
const uploadImageToCDN = async (imagePath: string): Promise<string> => {
|
||||
const stat = fs.statSync(imagePath);
|
||||
const fileBuffer = fs.readFileSync(imagePath);
|
||||
const fileSizeInBytes = stat.size;
|
||||
|
||||
// Get presigned URL for achievement image
|
||||
const response = await HydraApi.post<{
|
||||
presignedUrl: string;
|
||||
achievementImageUrl: string;
|
||||
@@ -27,7 +24,6 @@ const uploadImageToCDN = async (imagePath: string): Promise<string> => {
|
||||
|
||||
const mimeType = await fileTypeFromFile(imagePath);
|
||||
|
||||
// Upload to CDN
|
||||
await axios.put(response.presignedUrl, fileBuffer, {
|
||||
headers: {
|
||||
"Content-Type": mimeType?.mime,
|
||||
@@ -37,21 +33,16 @@ const uploadImageToCDN = async (imagePath: string): Promise<string> => {
|
||||
return response.achievementImageUrl;
|
||||
};
|
||||
|
||||
/**
|
||||
* Stores achievement image locally in the database
|
||||
*/
|
||||
|
||||
const storeImageLocally = async (imagePath: string): Promise<string> => {
|
||||
const fileBuffer = fs.readFileSync(imagePath);
|
||||
const base64Image = fileBuffer.toString("base64");
|
||||
const mimeType = await fileTypeFromFile(imagePath);
|
||||
|
||||
// Create a data URL for local storage
|
||||
return `data:${mimeType?.mime || "image/jpeg"};base64,${base64Image}`;
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates the achievement with the image URL via API
|
||||
*/
|
||||
|
||||
const updateAchievementWithImageUrl = async (
|
||||
shop: GameShop,
|
||||
gameId: string,
|
||||
@@ -64,9 +55,7 @@ const updateAchievementWithImageUrl = async (
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Main function for uploading achievement images (called from mergeAchievements)
|
||||
*/
|
||||
|
||||
export const uploadAchievementImage = async (
|
||||
gameId: string,
|
||||
achievementName: string,
|
||||
@@ -76,7 +65,6 @@ export const uploadAchievementImage = async (
|
||||
try {
|
||||
let imageUrl: string;
|
||||
|
||||
// Check if user has active subscription
|
||||
const hasSubscription = await db
|
||||
.get<string, User>(levelKeys.user, { valueEncoding: "json" })
|
||||
.then((user) => {
|
||||
@@ -86,7 +74,6 @@ export const uploadAchievementImage = async (
|
||||
.catch(() => false);
|
||||
|
||||
if (hasSubscription) {
|
||||
// Upload to CDN and update via API
|
||||
imageUrl = await uploadImageToCDN(imagePath);
|
||||
if (shop) {
|
||||
await updateAchievementWithImageUrl(
|
||||
@@ -100,7 +87,6 @@ export const uploadAchievementImage = async (
|
||||
`Achievement image uploaded to CDN for ${gameId}:${achievementName}`
|
||||
);
|
||||
} else {
|
||||
// Store locally
|
||||
imageUrl = await storeImageLocally(imagePath);
|
||||
logger.log(
|
||||
`Achievement image stored locally for ${gameId}:${achievementName}`
|
||||
@@ -117,9 +103,7 @@ export const uploadAchievementImage = async (
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* IPC event handler for uploading achievement images
|
||||
*/
|
||||
|
||||
const uploadAchievementImageEvent = async (
|
||||
_event: Electron.IpcMainInvokeEvent,
|
||||
params: {
|
||||
@@ -139,7 +123,6 @@ const uploadAchievementImageEvent = async (
|
||||
shop
|
||||
);
|
||||
|
||||
// Update local database with image URL
|
||||
const achievementKey = levelKeys.game(shop, gameId);
|
||||
const existingData = await gameAchievementsSublevel
|
||||
.get(achievementKey)
|
||||
@@ -152,7 +135,6 @@ const uploadAchievementImageEvent = async (
|
||||
});
|
||||
}
|
||||
|
||||
// Clean up the temporary screenshot file
|
||||
try {
|
||||
fs.unlinkSync(imagePath);
|
||||
} catch (error) {
|
||||
@@ -161,7 +143,6 @@ const uploadAchievementImageEvent = async (
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
// Clean up the temporary screenshot file even on error
|
||||
try {
|
||||
fs.unlinkSync(imagePath);
|
||||
} catch (cleanupError) {
|
||||
|
||||
@@ -33,7 +33,6 @@ export const getUnlockedAchievements = async (
|
||||
|
||||
const unlockedAchievements = cachedAchievements?.unlockedAchievements ?? [];
|
||||
|
||||
// Try to get user achievements with image URLs from remote API
|
||||
let remoteUserAchievements: UserAchievement[] = [];
|
||||
try {
|
||||
const userDetails = await db.get<string, any>(levelKeys.user, {
|
||||
@@ -51,7 +50,6 @@ export const getUnlockedAchievements = async (
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
// If API call fails, continue with local data only
|
||||
if (!(error instanceof UserNotLoggedInError)) {
|
||||
console.warn("Failed to fetch remote user achievements:", error);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import { logger } from "../logger";
|
||||
import { db, gameAchievementsSublevel, levelKeys } from "@main/level";
|
||||
import { AxiosError } from "axios";
|
||||
|
||||
|
||||
const getModifiedSinceHeader = (
|
||||
cachedAchievements: GameAchievement | undefined,
|
||||
userLanguage: string
|
||||
@@ -32,8 +31,7 @@ export const getGameAchievementData = async (
|
||||
|
||||
const cachedAchievements = await gameAchievementsSublevel.get(gameKey);
|
||||
|
||||
|
||||
if(cachedAchievements?.achievements && useCachedData) {
|
||||
if (cachedAchievements?.achievements && useCachedData) {
|
||||
return cachedAchievements.achievements;
|
||||
}
|
||||
|
||||
|
||||
@@ -190,21 +190,17 @@ export const mergeAchievements = async (
|
||||
);
|
||||
}
|
||||
|
||||
// Capture and upload screenshot AFTER achievements are synced to server
|
||||
if (
|
||||
newAchievements.length &&
|
||||
userPreferences.enableAchievementScreenshots === true
|
||||
) {
|
||||
try {
|
||||
// Import and trigger the upload process
|
||||
const { uploadAchievementImage } = await import(
|
||||
"@main/events/achievements/upload-achievement-image"
|
||||
);
|
||||
|
||||
// Upload the screenshot for each new achievement
|
||||
for (const achievement of newAchievements) {
|
||||
try {
|
||||
// Find the achievement data to get the display name
|
||||
const achievementData = achievementsData.find(
|
||||
(steamAchievement) => {
|
||||
return (
|
||||
@@ -217,7 +213,6 @@ export const mergeAchievements = async (
|
||||
const achievementDisplayName =
|
||||
achievementData?.displayName || achievement.name;
|
||||
|
||||
// Capture screenshot with game title and achievement name
|
||||
const screenshotPath =
|
||||
await ScreenshotService.captureDesktopScreenshot(
|
||||
game.title,
|
||||
|
||||
@@ -5,20 +5,17 @@ import { app } from "electron";
|
||||
import { logger } from "./logger";
|
||||
|
||||
export class ScreenshotService {
|
||||
private static readonly SCREENSHOT_QUALITY = 60; // Reduced for better compression
|
||||
private static readonly SCREENSHOT_QUALITY = 80;
|
||||
private static readonly SCREENSHOT_FORMAT = "jpeg";
|
||||
private static readonly MAX_WIDTH = 1280; // Maximum width for compression
|
||||
private static readonly MAX_HEIGHT = 720; // Maximum height for compression
|
||||
private static readonly MAX_WIDTH = 1280;
|
||||
private static readonly MAX_HEIGHT = 720;
|
||||
|
||||
|
||||
/**
|
||||
* Compresses an image by resizing and adjusting quality
|
||||
*/
|
||||
private static compressImage(
|
||||
image: Electron.NativeImage
|
||||
): Electron.NativeImage {
|
||||
const size = image.getSize();
|
||||
|
||||
// Calculate new dimensions while maintaining aspect ratio
|
||||
let newWidth = size.width;
|
||||
let newHeight = size.height;
|
||||
|
||||
@@ -34,7 +31,6 @@ export class ScreenshotService {
|
||||
}
|
||||
}
|
||||
|
||||
// Resize the image if dimensions changed
|
||||
if (newWidth !== size.width || newHeight !== size.height) {
|
||||
return image.resize({ width: newWidth, height: newHeight });
|
||||
}
|
||||
@@ -47,7 +43,6 @@ export class ScreenshotService {
|
||||
achievementName?: string
|
||||
): Promise<string> {
|
||||
try {
|
||||
// Get all available desktop sources
|
||||
const sources = await desktopCapturer.getSources({
|
||||
types: ["screen"],
|
||||
thumbnailSize: { width: 1920, height: 1080 },
|
||||
@@ -57,18 +52,14 @@ export class ScreenshotService {
|
||||
throw new Error("No desktop sources available for screenshot");
|
||||
}
|
||||
|
||||
// Use the primary screen (first source)
|
||||
const primaryScreen = sources[0];
|
||||
|
||||
// Convert the thumbnail to a higher quality image
|
||||
const originalImage = nativeImage.createFromDataURL(
|
||||
primaryScreen.thumbnail.toDataURL()
|
||||
);
|
||||
|
||||
// Compress the image to reduce file size
|
||||
const compressedImage = this.compressImage(originalImage);
|
||||
|
||||
// Create screenshots directory structure
|
||||
const userDataPath = app.getPath("userData");
|
||||
const screenshotsDir = path.join(userDataPath, "screenshots");
|
||||
|
||||
@@ -76,31 +67,26 @@ export class ScreenshotService {
|
||||
let filename: string;
|
||||
|
||||
if (gameTitle && achievementName) {
|
||||
// Create game-specific directory
|
||||
const sanitizedGameTitle = gameTitle.replace(/[<>:"/\\|?*]/g, "_");
|
||||
const gameDir = path.join(screenshotsDir, sanitizedGameTitle);
|
||||
finalDir = gameDir;
|
||||
|
||||
// Use achievement name as filename (sanitized)
|
||||
const sanitizedAchievementName = achievementName.replace(
|
||||
/[<>:"/\\|?*]/g,
|
||||
"_"
|
||||
);
|
||||
filename = `${sanitizedAchievementName}.${this.SCREENSHOT_FORMAT}`;
|
||||
} else {
|
||||
// Fallback to timestamp-based naming
|
||||
const timestamp = Date.now();
|
||||
filename = `achievement_screenshot_${timestamp}.${this.SCREENSHOT_FORMAT}`;
|
||||
}
|
||||
|
||||
// Ensure directory exists
|
||||
if (!fs.existsSync(finalDir)) {
|
||||
fs.mkdirSync(finalDir, { recursive: true });
|
||||
}
|
||||
|
||||
const screenshotPath = path.join(finalDir, filename);
|
||||
|
||||
// Save the compressed screenshot as JPEG with specified quality
|
||||
const jpegBuffer = compressedImage.toJPEG(this.SCREENSHOT_QUALITY);
|
||||
fs.writeFileSync(screenshotPath, jpegBuffer);
|
||||
|
||||
@@ -121,7 +107,6 @@ export class ScreenshotService {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get all files recursively from screenshots directory and subdirectories
|
||||
const getAllFiles = (
|
||||
dir: string
|
||||
): Array<{ name: string; path: string; mtime: Date }> => {
|
||||
@@ -133,7 +118,6 @@ export class ScreenshotService {
|
||||
const stat = fs.statSync(itemPath);
|
||||
|
||||
if (stat.isDirectory()) {
|
||||
// Recursively get files from subdirectories
|
||||
files.push(...getAllFiles(itemPath));
|
||||
} else if (item.endsWith(`.${this.SCREENSHOT_FORMAT}`)) {
|
||||
files.push({
|
||||
@@ -151,7 +135,6 @@ export class ScreenshotService {
|
||||
(a, b) => b.mtime.getTime() - a.mtime.getTime()
|
||||
);
|
||||
|
||||
// Keep only the 50 most recent screenshots (increased from 10 to accommodate multiple games)
|
||||
const filesToDelete = allFiles.slice(50);
|
||||
|
||||
for (const file of filesToDelete) {
|
||||
@@ -163,9 +146,8 @@ export class ScreenshotService {
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up empty directories
|
||||
const cleanupEmptyDirs = (dir: string) => {
|
||||
if (dir === screenshotsDir) return; // Don't delete the main screenshots directory
|
||||
if (dir === screenshotsDir) return;
|
||||
|
||||
try {
|
||||
const items = fs.readdirSync(dir);
|
||||
@@ -174,11 +156,9 @@ export class ScreenshotService {
|
||||
logger.log(`Cleaned up empty directory: ${dir}`);
|
||||
}
|
||||
} catch (error) {
|
||||
// Directory might not be empty or might not exist, ignore
|
||||
}
|
||||
};
|
||||
|
||||
// Check for empty game directories and clean them up
|
||||
const gameDirectories = fs
|
||||
.readdirSync(screenshotsDir)
|
||||
.map((item) => path.join(screenshotsDir, item))
|
||||
|
||||
@@ -100,7 +100,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Mobile responsiveness
|
||||
@media (max-width: 768px) {
|
||||
.fullscreen-image-modal {
|
||||
&__close-button {
|
||||
@@ -118,7 +117,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
/* Extra safeguard for very low viewport heights */
|
||||
@media (max-height: 420px) {
|
||||
.fullscreen-image-modal {
|
||||
&__close-button {
|
||||
|
||||
@@ -131,7 +131,6 @@ export function UserProfileContextProvider({
|
||||
getUserStats();
|
||||
getUserLibraryGames();
|
||||
|
||||
// Get current language for API call
|
||||
const currentLanguage = i18n.language.split("-")[0];
|
||||
const supportedLanguages = ["pt", "ru", "es"];
|
||||
const language = supportedLanguages.includes(currentLanguage)
|
||||
|
||||
Reference in New Issue
Block a user