ci: fix lint errors

This commit is contained in:
Moyasee
2025-10-20 01:45:00 +03:00
parent cc9d98c360
commit 8c0281844e
12 changed files with 296 additions and 183 deletions

View File

@@ -104,8 +104,6 @@ export const mergeAchievements = async (
publishNotification &&
userPreferences.achievementNotificationsEnabled !== false
) {
const filteredAchievements = newAchievements
.toSorted((a, b) => {
return a.unlockTime - b.unlockTime;
@@ -192,37 +190,57 @@ export const mergeAchievements = async (
}
// Capture and upload screenshot AFTER achievements are synced to server
if (newAchievements.length && userPreferences.enableAchievementScreenshots === true) {
if (
newAchievements.length &&
userPreferences.enableAchievementScreenshots === true
) {
try {
// Import and trigger the upload process
const { uploadAchievementImage } = await import("@main/events/achievements/upload-achievement-image");
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 (
achievement.name.toUpperCase() ===
steamAchievement.name.toUpperCase()
);
});
const achievementDisplayName = achievementData?.displayName || achievement.name;
// Capture screenshot with game title and achievement name
const screenshotPath = await ScreenshotService.captureDesktopScreenshot(
game.title,
achievementDisplayName
const achievementData = achievementsData.find(
(steamAchievement) => {
return (
achievement.name.toUpperCase() ===
steamAchievement.name.toUpperCase()
);
}
);
const achievementDisplayName =
achievementData?.displayName || achievement.name;
// Capture screenshot with game title and achievement name
const screenshotPath =
await ScreenshotService.captureDesktopScreenshot(
game.title,
achievementDisplayName
);
await uploadAchievementImage(
game.objectId,
achievement.name,
screenshotPath,
game.shop
);
await uploadAchievementImage(game.objectId, achievement.name, screenshotPath, game.shop);
} catch (error) {
achievementsLogger.error("Failed to upload achievement image", error);
achievementsLogger.error(
"Failed to upload achievement image",
error
);
}
}
} catch (error) {
achievementsLogger.error("Failed to capture screenshot for achievement", error);
achievementsLogger.error(
"Failed to capture screenshot for achievement",
error
);
}
}
})

View File

@@ -10,20 +10,21 @@ export class ScreenshotService {
private static readonly MAX_WIDTH = 1280; // Maximum width for compression
private static readonly MAX_HEIGHT = 720; // Maximum height for compression
/**
* Compresses an image by resizing and adjusting quality
*/
private static compressImage(image: Electron.NativeImage): Electron.NativeImage {
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;
if (newWidth > this.MAX_WIDTH || newHeight > this.MAX_HEIGHT) {
const aspectRatio = newWidth / newHeight;
if (newWidth > newHeight) {
newWidth = this.MAX_WIDTH;
newHeight = Math.round(newWidth / aspectRatio);
@@ -32,21 +33,24 @@ export class ScreenshotService {
newWidth = Math.round(newHeight * aspectRatio);
}
}
// Resize the image if dimensions changed
if (newWidth !== size.width || newHeight !== size.height) {
return image.resize({ width: newWidth, height: newHeight });
}
return image;
}
public static async captureDesktopScreenshot(gameTitle?: string, achievementName?: string): Promise<string> {
public static async captureDesktopScreenshot(
gameTitle?: string,
achievementName?: string
): Promise<string> {
try {
// Get all available desktop sources
const sources = await desktopCapturer.getSources({
types: ["screen"],
thumbnailSize: { width: 1920, height: 1080 }
thumbnailSize: { width: 1920, height: 1080 },
});
if (sources.length === 0) {
@@ -55,74 +59,79 @@ export class ScreenshotService {
// 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());
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");
let finalDir = screenshotsDir;
let filename: string;
if (gameTitle && achievementName) {
// Create game-specific directory
const sanitizedGameTitle = gameTitle.replace(/[<>:"/\\|?*]/g, '_');
const sanitizedGameTitle = gameTitle.replace(/[<>:"/\\|?*]/g, "_");
const gameDir = path.join(screenshotsDir, sanitizedGameTitle);
finalDir = gameDir;
// Use achievement name as filename (sanitized)
const sanitizedAchievementName = achievementName.replace(/[<>:"/\\|?*]/g, '_');
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);
logger.log(`Compressed screenshot saved to: ${screenshotPath}`);
return screenshotPath;
} catch (error) {
logger.error("Failed to capture desktop screenshot:", error);
throw error;
}
}
public static async cleanupOldScreenshots(): Promise<void> {
try {
const userDataPath = app.getPath("userData");
const screenshotsDir = path.join(userDataPath, "screenshots");
if (!fs.existsSync(screenshotsDir)) {
return;
}
// Get all files recursively from screenshots directory and subdirectories
const getAllFiles = (dir: string): Array<{name: string, path: string, mtime: Date}> => {
const files: Array<{name: string, path: string, mtime: Date}> = [];
const getAllFiles = (
dir: string
): Array<{ name: string; path: string; mtime: Date }> => {
const files: Array<{ name: string; path: string; mtime: Date }> = [];
const items = fs.readdirSync(dir);
for (const item of items) {
const itemPath = path.join(dir, item);
const stat = fs.statSync(itemPath);
if (stat.isDirectory()) {
// Recursively get files from subdirectories
files.push(...getAllFiles(itemPath));
@@ -130,20 +139,21 @@ export class ScreenshotService {
files.push({
name: item,
path: itemPath,
mtime: stat.mtime
mtime: stat.mtime,
});
}
}
return files;
};
const allFiles = getAllFiles(screenshotsDir)
.sort((a, b) => b.mtime.getTime() - a.mtime.getTime());
const allFiles = getAllFiles(screenshotsDir).sort(
(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) {
try {
fs.unlinkSync(file.path);
@@ -152,11 +162,11 @@ export class ScreenshotService {
logger.error(`Failed to delete screenshot ${file.name}:`, error);
}
}
// Clean up empty directories
const cleanupEmptyDirs = (dir: string) => {
if (dir === screenshotsDir) return; // Don't delete the main screenshots directory
try {
const items = fs.readdirSync(dir);
if (items.length === 0) {
@@ -167,24 +177,24 @@ export class ScreenshotService {
// 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))
.filter(itemPath => {
const gameDirectories = fs
.readdirSync(screenshotsDir)
.map((item) => path.join(screenshotsDir, item))
.filter((itemPath) => {
try {
return fs.statSync(itemPath).isDirectory();
} catch {
return false;
}
});
for (const gameDir of gameDirectories) {
cleanupEmptyDirs(gameDir);
}
} catch (error) {
logger.error("Failed to cleanup old screenshots:", error);
}
}
}
}

View File

@@ -1,4 +1,9 @@
import { User, type ProfileVisibility, type UserDetails, type UserPreferences } from "@types";
import {
User,
type ProfileVisibility,
type UserDetails,
type UserPreferences,
} from "@types";
import { HydraApi } from "../hydra-api";
import { UserNotLoggedInError } from "@shared";
import { logger } from "../logger";
@@ -13,7 +18,7 @@ export const getUserData = async () => {
levelKeys.userPreferences,
{ valueEncoding: "json" }
);
if (userPreferences?.language) {
// Map supported languages (pt, ru, es) or fallback to en
const supportedLanguages = ["pt", "ru", "es"];