From cacc4ca57a8aed418ca3faaa699857376b88ad7d Mon Sep 17 00:00:00 2001 From: shadowtosser Date: Sat, 20 Apr 2024 15:54:08 -0300 Subject: [PATCH 001/140] feat: add a modal to select game installation folder (pt and en translation) --- forge.config.ts | 6 +- src/locales/en/translation.json | 8 +- src/locales/pt/translation.json | 8 +- .../events/library/add-game-to-library.ts | 2 +- .../events/torrenting/start-game-download.ts | 6 +- src/preload.ts | 13 +- src/renderer/assets/lottie/settings.json | 1055 ++++++++++++++++- src/renderer/declaration.d.ts | 3 +- src/renderer/hooks/use-download.ts | 5 +- .../pages/game-details/game-details.tsx | 8 +- .../pages/game-details/repacks-modal.tsx | 20 +- .../game-details/select-folder-modal.css.tsx | 19 + .../game-details/select-folder-modal.tsx | 103 ++ 13 files changed, 1232 insertions(+), 24 deletions(-) create mode 100644 src/renderer/pages/game-details/select-folder-modal.css.tsx create mode 100644 src/renderer/pages/game-details/select-folder-modal.tsx diff --git a/forge.config.ts b/forge.config.ts index 21718764..94cfac57 100644 --- a/forge.config.ts +++ b/forge.config.ts @@ -20,7 +20,7 @@ const linuxPkgConfig = { icon: "images/icon.png", genericName: "Games Launcher", name: "hydra-launcher", - productName: "Hydra" + productName: "Hydra", }; const config: ForgeConfig = { @@ -50,10 +50,10 @@ const config: ForgeConfig = { }), new MakerZIP({}, ["darwin", "linux"]), new MakerRpm({ - options: linuxPkgConfig + options: linuxPkgConfig, }), new MakerDeb({ - options: linuxPkgConfig + options: linuxPkgConfig, }), ], publishers: [ diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index f59f1e87..a9fcb19d 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -77,7 +77,13 @@ "play": "Play", "deleting": "Deleting installer…", "close": "Close", - "playing_now": "Playing now" + "playing_now": "Playing now", + "change": "Change", + "select_folder_description": "Select the folder where the game will be installed", + "downloads_path": "Downloads path", + "select_folder_hint": "To change the default folder, access the", + "hydra_settings": "Hydra settings", + "download_now": "Download now" }, "activation": { "title": "Activate Hydra", diff --git a/src/locales/pt/translation.json b/src/locales/pt/translation.json index 145163b4..c2d24840 100644 --- a/src/locales/pt/translation.json +++ b/src/locales/pt/translation.json @@ -73,7 +73,13 @@ "not_played_yet": "Você ainda não jogou {{title}}", "close": "Fechar", "deleting": "Excluindo instalador…", - "playing_now": "Jogando agora" + "playing_now": "Jogando agora", + "change": "Mudar", + "select_folder_description": "Selecione a pasta em que o jogo será baixado", + "downloads_path": "Diretório do download", + "select_folder_hint": "Para trocar a pasta padrão, acesse as ", + "hydra_settings": "Configurações do Hydra", + "download_now": "Baixe agora" }, "activation": { "title": "Ativação", diff --git a/src/main/events/library/add-game-to-library.ts b/src/main/events/library/add-game-to-library.ts index 8680b29a..12e4c8bf 100644 --- a/src/main/events/library/add-game-to-library.ts +++ b/src/main/events/library/add-game-to-library.ts @@ -10,7 +10,7 @@ const addGameToLibrary = async ( _event: Electron.IpcMainInvokeEvent, objectID: string, title: string, - gameShop: GameShop, + gameShop: GameShop ) => { const iconUrl = await getImageBase64(await getSteamGameIconUrl(objectID)); diff --git a/src/main/events/torrenting/start-game-download.ts b/src/main/events/torrenting/start-game-download.ts index 570fd2ec..f661a956 100644 --- a/src/main/events/torrenting/start-game-download.ts +++ b/src/main/events/torrenting/start-game-download.ts @@ -5,7 +5,6 @@ import { GameStatus } from "@main/constants"; import { registerEvent } from "../register-event"; import type { GameShop } from "@types"; -import { getDownloadsPath } from "../helpers/get-downloads-path"; import { getImageBase64 } from "@main/helpers"; import { In } from "typeorm"; @@ -14,7 +13,8 @@ const startGameDownload = async ( repackId: number, objectID: string, title: string, - gameShop: GameShop + gameShop: GameShop, + downloadPath: string ) => { const [game, repack] = await Promise.all([ gameRepository.findOne({ @@ -37,7 +37,7 @@ const startGameDownload = async ( writePipe.write({ action: "pause" }); - const downloadsPath = game?.downloadPath ?? (await getDownloadsPath()); + const downloadsPath = game?.downloadPath ?? downloadPath; await gameRepository.update( { diff --git a/src/preload.ts b/src/preload.ts index 93acde24..7ee37d0b 100644 --- a/src/preload.ts +++ b/src/preload.ts @@ -15,8 +15,17 @@ contextBridge.exposeInMainWorld("electron", { repackId: number, objectID: string, title: string, - shop: GameShop - ) => ipcRenderer.invoke("startGameDownload", repackId, objectID, title, shop), + shop: GameShop, + downloadPath: string + ) => + ipcRenderer.invoke( + "startGameDownload", + repackId, + objectID, + title, + shop, + downloadPath + ), cancelGameDownload: (gameId: number) => ipcRenderer.invoke("cancelGameDownload", gameId), pauseGameDownload: (gameId: number) => diff --git a/src/renderer/assets/lottie/settings.json b/src/renderer/assets/lottie/settings.json index 4d37e53a..92fa645e 100644 --- a/src/renderer/assets/lottie/settings.json +++ b/src/renderer/assets/lottie/settings.json @@ -1 +1,1054 @@ -{"v":"4.8.0","meta":{"g":"LottieFiles AE 3.5.6","a":"","k":"","d":"","tc":""},"fr":60,"ip":0,"op":120,"w":900,"h":900,"nm":"Pre-comp 1","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"estrela Outlines 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.933],"y":[0]},"t":0,"s":[0]},{"t":60,"s":[180]}],"ix":10},"p":{"a":0,"k":[450,450,0],"ix":2},"a":{"a":0,"k":[308.5,333,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.011,34.469],[34.47,-0.012],[-0.011,-34.469],[-34.47,0.011]],"o":[[-0.012,-34.47],[-34.469,0.011],[0.012,34.47],[34.469,-0.012]],"v":[[62.333,0.005],[-0.101,-62.387],[-62.493,0.047],[-0.059,62.439]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,-68.917],[68.916,0],[0,68.916],[-68.916,0]],"o":[[0,68.916],[-68.916,0],[0,-68.917],[68.916,0]],"v":[[124.725,0.005],[-0.059,124.789],[-124.843,0.005],[-0.059,-124.779]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[15.804,-1.372],[1.206,-4.575],[0,0],[18.676,-9.234],[6.656,-4.451],[23.252,6.364],[0,0],[0.832,-1.206],[6.697,-14.392],[-3.327,-3.328],[0,0],[1.331,-20.755],[-0.499,-8.062],[17.095,-16.887],[0,0],[-0.582,-1.289],[-9.151,-12.977],[-4.575,1.248],[0,0],[-17.345,-11.563],[-7.196,-3.578],[-6.114,-23.293],[0,0],[-1.497,-0.124],[-15.804,1.373],[-1.207,4.575],[0,0],[-18.676,9.234],[-6.655,4.451],[-23.251,-6.364],[0,0],[-0.832,1.206],[-6.739,14.392],[3.327,3.328],[0,0],[-1.331,20.755],[0.499,8.061],[-17.095,16.887],[0,0],[0.582,1.289],[9.144,12.981],[4.576,-1.248],[0,0],[17.345,11.563],[7.202,3.563],[6.114,23.293],[0,0],[1.498,0.125]],"o":[[-1.497,0.125],[0,0],[-6.114,23.334],[-7.196,3.578],[-17.345,11.563],[0,0],[-4.534,-1.248],[-9.151,12.978],[-0.582,1.289],[0,0],[17.095,16.887],[-0.5,8.062],[1.331,20.755],[0,0],[-3.369,3.328],[6.738,14.392],[0.832,1.248],[0,0],[23.293,-6.364],[6.697,4.451],[18.593,9.234],[0,0],[1.206,4.533],[15.804,1.373],[1.498,-0.124],[0,0],[6.114,-23.335],[7.196,-3.578],[17.345,-11.563],[0,0],[4.534,1.206],[9.151,-13.019],[0.582,-1.289],[0,0],[-17.095,-16.887],[0.499,-8.062],[-1.331,-20.756],[0,0],[3.369,-3.328],[-6.715,-14.39],[-0.832,-1.248],[0,0],[-23.293,6.364],[-6.676,-4.47],[-18.592,-9.234],[0,0],[-1.207,-4.575],[-15.804,-1.372]],"v":[[-23.81,-269.32],[-29.508,-263.247],[-41.529,-217.285],[-83.04,-167.829],[-103.838,-155.766],[-167.436,-144.536],[-213.314,-157.139],[-221.425,-155.267],[-245.259,-114.089],[-242.805,-106.185],[-208.905,-72.66],[-186.86,-12.099],[-186.86,12.109],[-208.905,72.671],[-242.805,106.195],[-245.259,114.099],[-221.425,155.236],[-213.314,157.15],[-167.477,144.547],[-103.838,155.777],[-82.999,167.839],[-41.529,217.295],[-29.508,263.257],[-23.81,269.329],[23.691,269.329],[29.39,263.257],[41.411,217.295],[82.922,167.839],[103.719,155.777],[167.317,144.547],[213.196,157.15],[221.307,155.277],[245.141,114.099],[242.687,106.195],[208.787,72.671],[186.742,12.109],[186.742,-12.098],[208.787,-72.66],[242.687,-106.185],[245.141,-114.089],[221.307,-155.225],[213.196,-157.139],[167.359,-144.536],[103.719,-155.766],[82.88,-167.828],[41.411,-217.285],[29.39,-263.247],[23.691,-269.32]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[-9.816,0],[-9.697,-0.846],[-7.071,-26.828],[0,0],[-5.532,-2.745],[-8.902,-5.948],[-2.745,0.79],[0,0],[-17.802,-25.331],[-8.236,-17.72],[19.758,-19.508],[0,0],[-0.416,-6.114],[0.666,-10.69],[-2.079,-1.997],[0,0],[13.102,-28.076],[11.232,-15.979],[26.787,7.363],[0,0],[5.117,-3.411],[9.602,-4.741],[0.707,-2.745],[0,0],[30.904,-2.663],[19.401,1.705],[7.03,26.87],[0,0],[5.532,2.745],[8.891,5.969],[2.746,-0.79],[0,0],[17.802,25.332],[8.277,17.703],[-19.716,19.508],[0,0],[0.416,6.114],[-0.666,10.693],[2.08,1.997],[0,0],[-13.102,28.076],[-11.242,15.972],[-26.787,-7.363],[0,0],[-5.116,3.411],[-9.608,4.742],[-0.707,2.745],[0,0],[-30.905,2.704]],"o":[[9.733,0.014],[30.904,2.662],[0,0],[0.749,2.745],[9.609,4.742],[5.116,3.411],[0,0],[26.787,-7.321],[11.231,16.014],[13.102,28.076],[0,0],[-2.038,1.997],[0.666,10.69],[-0.416,6.114],[0,0],[19.758,19.508],[-8.252,17.703],[-17.802,25.373],[0,0],[-2.787,-0.79],[-8.902,5.952],[-5.532,2.745],[0,0],[-6.987,26.87],[-19.402,1.705],[-30.905,-2.663],[0,0],[-0.748,-2.745],[-9.611,-4.723],[-5.116,-3.411],[0,0],[-26.786,7.321],[-11.208,-16.008],[-13.102,-28.076],[0,0],[2.08,-1.997],[-0.666,-10.693],[0.416,-6.114],[0,0],[-19.716,-19.508],[8.241,-17.709],[17.802,-25.373],[0,0],[2.787,0.79],[8.901,-5.948],[5.532,-2.745],[0,0],[6.988,-26.87],[9.608,-0.832]],"v":[[-0.059,-332.751],[29.099,-331.462],[89.785,-279.095],[101.764,-233.049],[110.582,-223.733],[138.368,-207.676],[150.804,-204.723],[196.683,-217.327],[272.385,-191.123],[301.668,-140.459],[286.527,-61.805],[252.669,-28.28],[249.009,-16.051],[249.009,16.061],[252.669,28.289],[286.527,61.815],[301.668,140.47],[272.385,191.09],[196.683,217.295],[150.846,204.734],[138.367,207.687],[110.582,223.743],[101.806,233.059],[89.743,279.063],[29.099,331.473],[-29.217,331.473],[-89.862,279.063],[-101.883,233.059],[-110.701,223.743],[-138.486,207.687],[-150.923,204.734],[-196.802,217.336],[-272.504,191.132],[-301.786,140.47],[-286.687,61.815],[-252.788,28.289],[-249.127,16.061],[-249.127,-16.051],[-252.788,-28.28],[-286.687,-61.805],[-301.786,-140.459],[-272.504,-191.08],[-196.801,-217.285],[-150.964,-204.723],[-138.486,-207.676],[-110.701,-223.733],[-101.924,-233.049],[-89.862,-279.053],[-29.217,-331.504]],"c":true},"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.898460657456,0.889815326765,0.896223060758,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[308.077,333.249],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":8,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"estrela Outlines 2 Comp 1","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[450,450,0],"ix":2},"a":{"a":0,"k":[450,450,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[1,1,0.333],"y":[0,0,0]},"t":0,"s":[100,100,100]},{"i":{"x":[0,0,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":30,"s":[80,80,100]},{"t":60,"s":[100,100,100]}],"ix":6}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"a":0,"k":{"i":[[89.47,0],[0,-89.47],[-89.47,0],[0,89.47]],"o":[[-89.47,0],[0,89.47],[89.47,0],[0,-89.47]],"v":[[446,286],[284,448],[446,610],[608,448]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"}],"w":900,"h":900,"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"estrela Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.84],"y":[-1.753]},"o":{"x":[0],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.361],"y":[1]},"o":{"x":[0],"y":[0]},"t":28,"s":[15]},{"t":60,"s":[180]}],"ix":10},"p":{"a":0,"k":[450,450,0],"ix":2},"a":{"a":0,"k":[308.5,333,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.011,34.469],[34.47,-0.012],[-0.011,-34.469],[-34.47,0.011]],"o":[[-0.012,-34.47],[-34.469,0.011],[0.012,34.47],[34.469,-0.012]],"v":[[62.333,0.005],[-0.101,-62.387],[-62.493,0.047],[-0.059,62.439]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,-68.917],[68.916,0],[0,68.916],[-68.916,0]],"o":[[0,68.916],[-68.916,0],[0,-68.917],[68.916,0]],"v":[[124.725,0.005],[-0.059,124.789],[-124.843,0.005],[-0.059,-124.779]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[15.804,-1.372],[1.206,-4.575],[0,0],[18.676,-9.234],[6.656,-4.451],[23.252,6.364],[0,0],[0.832,-1.206],[6.697,-14.392],[-3.327,-3.328],[0,0],[1.331,-20.755],[-0.499,-8.062],[17.095,-16.887],[0,0],[-0.582,-1.289],[-9.151,-12.977],[-4.575,1.248],[0,0],[-17.345,-11.563],[-7.196,-3.578],[-6.114,-23.293],[0,0],[-1.497,-0.124],[-15.804,1.373],[-1.207,4.575],[0,0],[-18.676,9.234],[-6.655,4.451],[-23.251,-6.364],[0,0],[-0.832,1.206],[-6.739,14.392],[3.327,3.328],[0,0],[-1.331,20.755],[0.499,8.061],[-17.095,16.887],[0,0],[0.582,1.289],[9.144,12.981],[4.576,-1.248],[0,0],[17.345,11.563],[7.202,3.563],[6.114,23.293],[0,0],[1.498,0.125]],"o":[[-1.497,0.125],[0,0],[-6.114,23.334],[-7.196,3.578],[-17.345,11.563],[0,0],[-4.534,-1.248],[-9.151,12.978],[-0.582,1.289],[0,0],[17.095,16.887],[-0.5,8.062],[1.331,20.755],[0,0],[-3.369,3.328],[6.738,14.392],[0.832,1.248],[0,0],[23.293,-6.364],[6.697,4.451],[18.593,9.234],[0,0],[1.206,4.533],[15.804,1.373],[1.498,-0.124],[0,0],[6.114,-23.335],[7.196,-3.578],[17.345,-11.563],[0,0],[4.534,1.206],[9.151,-13.019],[0.582,-1.289],[0,0],[-17.095,-16.887],[0.499,-8.062],[-1.331,-20.756],[0,0],[3.369,-3.328],[-6.715,-14.39],[-0.832,-1.248],[0,0],[-23.293,6.364],[-6.676,-4.47],[-18.592,-9.234],[0,0],[-1.207,-4.575],[-15.804,-1.372]],"v":[[-23.81,-269.32],[-29.508,-263.247],[-41.529,-217.285],[-83.04,-167.829],[-103.838,-155.766],[-167.436,-144.536],[-213.314,-157.139],[-221.425,-155.267],[-245.259,-114.089],[-242.805,-106.185],[-208.905,-72.66],[-186.86,-12.099],[-186.86,12.109],[-208.905,72.671],[-242.805,106.195],[-245.259,114.099],[-221.425,155.236],[-213.314,157.15],[-167.477,144.547],[-103.838,155.777],[-82.999,167.839],[-41.529,217.295],[-29.508,263.257],[-23.81,269.329],[23.691,269.329],[29.39,263.257],[41.411,217.295],[82.922,167.839],[103.719,155.777],[167.317,144.547],[213.196,157.15],[221.307,155.277],[245.141,114.099],[242.687,106.195],[208.787,72.671],[186.742,12.109],[186.742,-12.098],[208.787,-72.66],[242.687,-106.185],[245.141,-114.089],[221.307,-155.225],[213.196,-157.139],[167.359,-144.536],[103.719,-155.766],[82.88,-167.828],[41.411,-217.285],[29.39,-263.247],[23.691,-269.32]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[-9.816,0],[-9.697,-0.846],[-7.071,-26.828],[0,0],[-5.532,-2.745],[-8.902,-5.948],[-2.745,0.79],[0,0],[-17.802,-25.331],[-8.236,-17.72],[19.758,-19.508],[0,0],[-0.416,-6.114],[0.666,-10.69],[-2.079,-1.997],[0,0],[13.102,-28.076],[11.232,-15.979],[26.787,7.363],[0,0],[5.117,-3.411],[9.602,-4.741],[0.707,-2.745],[0,0],[30.904,-2.663],[19.401,1.705],[7.03,26.87],[0,0],[5.532,2.745],[8.891,5.969],[2.746,-0.79],[0,0],[17.802,25.332],[8.277,17.703],[-19.716,19.508],[0,0],[0.416,6.114],[-0.666,10.693],[2.08,1.997],[0,0],[-13.102,28.076],[-11.242,15.972],[-26.787,-7.363],[0,0],[-5.116,3.411],[-9.608,4.742],[-0.707,2.745],[0,0],[-30.905,2.704]],"o":[[9.733,0.014],[30.904,2.662],[0,0],[0.749,2.745],[9.609,4.742],[5.116,3.411],[0,0],[26.787,-7.321],[11.231,16.014],[13.102,28.076],[0,0],[-2.038,1.997],[0.666,10.69],[-0.416,6.114],[0,0],[19.758,19.508],[-8.252,17.703],[-17.802,25.373],[0,0],[-2.787,-0.79],[-8.902,5.952],[-5.532,2.745],[0,0],[-6.987,26.87],[-19.402,1.705],[-30.905,-2.663],[0,0],[-0.748,-2.745],[-9.611,-4.723],[-5.116,-3.411],[0,0],[-26.786,7.321],[-11.208,-16.008],[-13.102,-28.076],[0,0],[2.08,-1.997],[-0.666,-10.693],[0.416,-6.114],[0,0],[-19.716,-19.508],[8.241,-17.709],[17.802,-25.373],[0,0],[2.787,0.79],[8.901,-5.948],[5.532,-2.745],[0,0],[6.988,-26.87],[9.608,-0.832]],"v":[[-0.059,-332.751],[29.099,-331.462],[89.785,-279.095],[101.764,-233.049],[110.582,-223.733],[138.368,-207.676],[150.804,-204.723],[196.683,-217.327],[272.385,-191.123],[301.668,-140.459],[286.527,-61.805],[252.669,-28.28],[249.009,-16.051],[249.009,16.061],[252.669,28.289],[286.527,61.815],[301.668,140.47],[272.385,191.09],[196.683,217.295],[150.846,204.734],[138.367,207.687],[110.582,223.743],[101.806,233.059],[89.743,279.063],[29.099,331.473],[-29.217,331.473],[-89.862,279.063],[-101.883,233.059],[-110.701,223.743],[-138.486,207.687],[-150.923,204.734],[-196.802,217.336],[-272.504,191.132],[-301.786,140.47],[-286.687,61.815],[-252.788,28.289],[-249.127,16.061],[-249.127,-16.051],[-252.788,-28.28],[-286.687,-61.805],[-301.786,-140.459],[-272.504,-191.08],[-196.801,-217.285],[-150.964,-204.723],[-138.486,-207.676],[-110.701,-223.733],[-101.924,-233.049],[-89.862,-279.053],[-29.217,-331.504]],"c":true},"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.898460657456,0.889815326765,0.896223060758,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[308.077,333.249],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":8,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":0,"bm":0}],"markers":[]} \ No newline at end of file +{ + "v": "4.8.0", + "meta": { "g": "LottieFiles AE 3.5.6", "a": "", "k": "", "d": "", "tc": "" }, + "fr": 60, + "ip": 0, + "op": 120, + "w": 900, + "h": 900, + "nm": "Pre-comp 1", + "ddd": 0, + "assets": [ + { + "id": "comp_0", + "layers": [ + { + "ddd": 0, + "ind": 1, + "ty": 4, + "nm": "estrela Outlines 2", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100, "ix": 11 }, + "r": { + "a": 1, + "k": [ + { + "i": { "x": [0.667], "y": [1] }, + "o": { "x": [0.933], "y": [0] }, + "t": 0, + "s": [0] + }, + { "t": 60, "s": [180] } + ], + "ix": 10 + }, + "p": { "a": 0, "k": [450, 450, 0], "ix": 2 }, + "a": { "a": 0, "k": [308.5, 333, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100, 100], "ix": 6 } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ix": 1, + "ks": { + "a": 0, + "k": { + "i": [ + [0.011, 34.469], + [34.47, -0.012], + [-0.011, -34.469], + [-34.47, 0.011] + ], + "o": [ + [-0.012, -34.47], + [-34.469, 0.011], + [0.012, 34.47], + [34.469, -0.012] + ], + "v": [ + [62.333, 0.005], + [-0.101, -62.387], + [-62.493, 0.047], + [-0.059, 62.439] + ], + "c": true + }, + "ix": 2 + }, + "nm": "Path 1", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ind": 1, + "ty": "sh", + "ix": 2, + "ks": { + "a": 0, + "k": { + "i": [ + [0, -68.917], + [68.916, 0], + [0, 68.916], + [-68.916, 0] + ], + "o": [ + [0, 68.916], + [-68.916, 0], + [0, -68.917], + [68.916, 0] + ], + "v": [ + [124.725, 0.005], + [-0.059, 124.789], + [-124.843, 0.005], + [-0.059, -124.779] + ], + "c": true + }, + "ix": 2 + }, + "nm": "Path 2", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ind": 2, + "ty": "sh", + "ix": 3, + "ks": { + "a": 0, + "k": { + "i": [ + [15.804, -1.372], + [1.206, -4.575], + [0, 0], + [18.676, -9.234], + [6.656, -4.451], + [23.252, 6.364], + [0, 0], + [0.832, -1.206], + [6.697, -14.392], + [-3.327, -3.328], + [0, 0], + [1.331, -20.755], + [-0.499, -8.062], + [17.095, -16.887], + [0, 0], + [-0.582, -1.289], + [-9.151, -12.977], + [-4.575, 1.248], + [0, 0], + [-17.345, -11.563], + [-7.196, -3.578], + [-6.114, -23.293], + [0, 0], + [-1.497, -0.124], + [-15.804, 1.373], + [-1.207, 4.575], + [0, 0], + [-18.676, 9.234], + [-6.655, 4.451], + [-23.251, -6.364], + [0, 0], + [-0.832, 1.206], + [-6.739, 14.392], + [3.327, 3.328], + [0, 0], + [-1.331, 20.755], + [0.499, 8.061], + [-17.095, 16.887], + [0, 0], + [0.582, 1.289], + [9.144, 12.981], + [4.576, -1.248], + [0, 0], + [17.345, 11.563], + [7.202, 3.563], + [6.114, 23.293], + [0, 0], + [1.498, 0.125] + ], + "o": [ + [-1.497, 0.125], + [0, 0], + [-6.114, 23.334], + [-7.196, 3.578], + [-17.345, 11.563], + [0, 0], + [-4.534, -1.248], + [-9.151, 12.978], + [-0.582, 1.289], + [0, 0], + [17.095, 16.887], + [-0.5, 8.062], + [1.331, 20.755], + [0, 0], + [-3.369, 3.328], + [6.738, 14.392], + [0.832, 1.248], + [0, 0], + [23.293, -6.364], + [6.697, 4.451], + [18.593, 9.234], + [0, 0], + [1.206, 4.533], + [15.804, 1.373], + [1.498, -0.124], + [0, 0], + [6.114, -23.335], + [7.196, -3.578], + [17.345, -11.563], + [0, 0], + [4.534, 1.206], + [9.151, -13.019], + [0.582, -1.289], + [0, 0], + [-17.095, -16.887], + [0.499, -8.062], + [-1.331, -20.756], + [0, 0], + [3.369, -3.328], + [-6.715, -14.39], + [-0.832, -1.248], + [0, 0], + [-23.293, 6.364], + [-6.676, -4.47], + [-18.592, -9.234], + [0, 0], + [-1.207, -4.575], + [-15.804, -1.372] + ], + "v": [ + [-23.81, -269.32], + [-29.508, -263.247], + [-41.529, -217.285], + [-83.04, -167.829], + [-103.838, -155.766], + [-167.436, -144.536], + [-213.314, -157.139], + [-221.425, -155.267], + [-245.259, -114.089], + [-242.805, -106.185], + [-208.905, -72.66], + [-186.86, -12.099], + [-186.86, 12.109], + [-208.905, 72.671], + [-242.805, 106.195], + [-245.259, 114.099], + [-221.425, 155.236], + [-213.314, 157.15], + [-167.477, 144.547], + [-103.838, 155.777], + [-82.999, 167.839], + [-41.529, 217.295], + [-29.508, 263.257], + [-23.81, 269.329], + [23.691, 269.329], + [29.39, 263.257], + [41.411, 217.295], + [82.922, 167.839], + [103.719, 155.777], + [167.317, 144.547], + [213.196, 157.15], + [221.307, 155.277], + [245.141, 114.099], + [242.687, 106.195], + [208.787, 72.671], + [186.742, 12.109], + [186.742, -12.098], + [208.787, -72.66], + [242.687, -106.185], + [245.141, -114.089], + [221.307, -155.225], + [213.196, -157.139], + [167.359, -144.536], + [103.719, -155.766], + [82.88, -167.828], + [41.411, -217.285], + [29.39, -263.247], + [23.691, -269.32] + ], + "c": true + }, + "ix": 2 + }, + "nm": "Path 3", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ind": 3, + "ty": "sh", + "ix": 4, + "ks": { + "a": 0, + "k": { + "i": [ + [-9.816, 0], + [-9.697, -0.846], + [-7.071, -26.828], + [0, 0], + [-5.532, -2.745], + [-8.902, -5.948], + [-2.745, 0.79], + [0, 0], + [-17.802, -25.331], + [-8.236, -17.72], + [19.758, -19.508], + [0, 0], + [-0.416, -6.114], + [0.666, -10.69], + [-2.079, -1.997], + [0, 0], + [13.102, -28.076], + [11.232, -15.979], + [26.787, 7.363], + [0, 0], + [5.117, -3.411], + [9.602, -4.741], + [0.707, -2.745], + [0, 0], + [30.904, -2.663], + [19.401, 1.705], + [7.03, 26.87], + [0, 0], + [5.532, 2.745], + [8.891, 5.969], + [2.746, -0.79], + [0, 0], + [17.802, 25.332], + [8.277, 17.703], + [-19.716, 19.508], + [0, 0], + [0.416, 6.114], + [-0.666, 10.693], + [2.08, 1.997], + [0, 0], + [-13.102, 28.076], + [-11.242, 15.972], + [-26.787, -7.363], + [0, 0], + [-5.116, 3.411], + [-9.608, 4.742], + [-0.707, 2.745], + [0, 0], + [-30.905, 2.704] + ], + "o": [ + [9.733, 0.014], + [30.904, 2.662], + [0, 0], + [0.749, 2.745], + [9.609, 4.742], + [5.116, 3.411], + [0, 0], + [26.787, -7.321], + [11.231, 16.014], + [13.102, 28.076], + [0, 0], + [-2.038, 1.997], + [0.666, 10.69], + [-0.416, 6.114], + [0, 0], + [19.758, 19.508], + [-8.252, 17.703], + [-17.802, 25.373], + [0, 0], + [-2.787, -0.79], + [-8.902, 5.952], + [-5.532, 2.745], + [0, 0], + [-6.987, 26.87], + [-19.402, 1.705], + [-30.905, -2.663], + [0, 0], + [-0.748, -2.745], + [-9.611, -4.723], + [-5.116, -3.411], + [0, 0], + [-26.786, 7.321], + [-11.208, -16.008], + [-13.102, -28.076], + [0, 0], + [2.08, -1.997], + [-0.666, -10.693], + [0.416, -6.114], + [0, 0], + [-19.716, -19.508], + [8.241, -17.709], + [17.802, -25.373], + [0, 0], + [2.787, 0.79], + [8.901, -5.948], + [5.532, -2.745], + [0, 0], + [6.988, -26.87], + [9.608, -0.832] + ], + "v": [ + [-0.059, -332.751], + [29.099, -331.462], + [89.785, -279.095], + [101.764, -233.049], + [110.582, -223.733], + [138.368, -207.676], + [150.804, -204.723], + [196.683, -217.327], + [272.385, -191.123], + [301.668, -140.459], + [286.527, -61.805], + [252.669, -28.28], + [249.009, -16.051], + [249.009, 16.061], + [252.669, 28.289], + [286.527, 61.815], + [301.668, 140.47], + [272.385, 191.09], + [196.683, 217.295], + [150.846, 204.734], + [138.367, 207.687], + [110.582, 223.743], + [101.806, 233.059], + [89.743, 279.063], + [29.099, 331.473], + [-29.217, 331.473], + [-89.862, 279.063], + [-101.883, 233.059], + [-110.701, 223.743], + [-138.486, 207.687], + [-150.923, 204.734], + [-196.802, 217.336], + [-272.504, 191.132], + [-301.786, 140.47], + [-286.687, 61.815], + [-252.788, 28.289], + [-249.127, 16.061], + [-249.127, -16.051], + [-252.788, -28.28], + [-286.687, -61.805], + [-301.786, -140.459], + [-272.504, -191.08], + [-196.801, -217.285], + [-150.964, -204.723], + [-138.486, -207.676], + [-110.701, -223.733], + [-101.924, -233.049], + [-89.862, -279.053], + [-29.217, -331.504] + ], + "c": true + }, + "ix": 2 + }, + "nm": "Path 4", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ty": "mm", + "mm": 1, + "nm": "Merge Paths 1", + "mn": "ADBE Vector Filter - Merge", + "hd": false + }, + { + "ty": "fl", + "c": { + "a": 0, + "k": [0.898460657456, 0.889815326765, 0.896223060758, 1], + "ix": 4 + }, + "o": { "a": 0, "k": 100, "ix": 5 }, + "r": 1, + "bm": 0, + "nm": "Fill 1", + "mn": "ADBE Vector Graphic - Fill", + "hd": false + }, + { + "ty": "tr", + "p": { "a": 0, "k": [308.077, 333.249], "ix": 2 }, + "a": { "a": 0, "k": [0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100], "ix": 3 }, + "r": { "a": 0, "k": 0, "ix": 6 }, + "o": { "a": 0, "k": 100, "ix": 7 }, + "sk": { "a": 0, "k": 0, "ix": 4 }, + "sa": { "a": 0, "k": 0, "ix": 5 }, + "nm": "Transform" + } + ], + "nm": "Group 1", + "np": 8, + "cix": 2, + "bm": 0, + "ix": 1, + "mn": "ADBE Vector Group", + "hd": false + } + ], + "ip": 0, + "op": 120, + "st": 0, + "bm": 0 + } + ] + } + ], + "layers": [ + { + "ddd": 0, + "ind": 1, + "ty": 0, + "nm": "estrela Outlines 2 Comp 1", + "refId": "comp_0", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100, "ix": 11 }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "p": { "a": 0, "k": [450, 450, 0], "ix": 2 }, + "a": { "a": 0, "k": [450, 450, 0], "ix": 1 }, + "s": { + "a": 1, + "k": [ + { + "i": { "x": [0.667, 0.667, 0.667], "y": [1, 1, 1] }, + "o": { "x": [1, 1, 0.333], "y": [0, 0, 0] }, + "t": 0, + "s": [100, 100, 100] + }, + { + "i": { "x": [0, 0, 0.667], "y": [1, 1, 1] }, + "o": { "x": [0.333, 0.333, 0.333], "y": [0, 0, 0] }, + "t": 30, + "s": [80, 80, 100] + }, + { "t": 60, "s": [100, 100, 100] } + ], + "ix": 6 + } + }, + "ao": 0, + "hasMask": true, + "masksProperties": [ + { + "inv": false, + "mode": "a", + "pt": { + "a": 0, + "k": { + "i": [ + [89.47, 0], + [0, -89.47], + [-89.47, 0], + [0, 89.47] + ], + "o": [ + [-89.47, 0], + [0, 89.47], + [89.47, 0], + [0, -89.47] + ], + "v": [ + [446, 286], + [284, 448], + [446, 610], + [608, 448] + ], + "c": true + }, + "ix": 1 + }, + "o": { "a": 0, "k": 100, "ix": 3 }, + "x": { "a": 0, "k": 0, "ix": 4 }, + "nm": "Mask 1" + } + ], + "w": 900, + "h": 900, + "ip": 0, + "op": 120, + "st": 0, + "bm": 0 + }, + { + "ddd": 0, + "ind": 2, + "ty": 4, + "nm": "estrela Outlines", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100, "ix": 11 }, + "r": { + "a": 1, + "k": [ + { + "i": { "x": [0.84], "y": [-1.753] }, + "o": { "x": [0], "y": [0] }, + "t": 0, + "s": [0] + }, + { + "i": { "x": [0.361], "y": [1] }, + "o": { "x": [0], "y": [0] }, + "t": 28, + "s": [15] + }, + { "t": 60, "s": [180] } + ], + "ix": 10 + }, + "p": { "a": 0, "k": [450, 450, 0], "ix": 2 }, + "a": { "a": 0, "k": [308.5, 333, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100, 100], "ix": 6 } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ix": 1, + "ks": { + "a": 0, + "k": { + "i": [ + [0.011, 34.469], + [34.47, -0.012], + [-0.011, -34.469], + [-34.47, 0.011] + ], + "o": [ + [-0.012, -34.47], + [-34.469, 0.011], + [0.012, 34.47], + [34.469, -0.012] + ], + "v": [ + [62.333, 0.005], + [-0.101, -62.387], + [-62.493, 0.047], + [-0.059, 62.439] + ], + "c": true + }, + "ix": 2 + }, + "nm": "Path 1", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ind": 1, + "ty": "sh", + "ix": 2, + "ks": { + "a": 0, + "k": { + "i": [ + [0, -68.917], + [68.916, 0], + [0, 68.916], + [-68.916, 0] + ], + "o": [ + [0, 68.916], + [-68.916, 0], + [0, -68.917], + [68.916, 0] + ], + "v": [ + [124.725, 0.005], + [-0.059, 124.789], + [-124.843, 0.005], + [-0.059, -124.779] + ], + "c": true + }, + "ix": 2 + }, + "nm": "Path 2", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ind": 2, + "ty": "sh", + "ix": 3, + "ks": { + "a": 0, + "k": { + "i": [ + [15.804, -1.372], + [1.206, -4.575], + [0, 0], + [18.676, -9.234], + [6.656, -4.451], + [23.252, 6.364], + [0, 0], + [0.832, -1.206], + [6.697, -14.392], + [-3.327, -3.328], + [0, 0], + [1.331, -20.755], + [-0.499, -8.062], + [17.095, -16.887], + [0, 0], + [-0.582, -1.289], + [-9.151, -12.977], + [-4.575, 1.248], + [0, 0], + [-17.345, -11.563], + [-7.196, -3.578], + [-6.114, -23.293], + [0, 0], + [-1.497, -0.124], + [-15.804, 1.373], + [-1.207, 4.575], + [0, 0], + [-18.676, 9.234], + [-6.655, 4.451], + [-23.251, -6.364], + [0, 0], + [-0.832, 1.206], + [-6.739, 14.392], + [3.327, 3.328], + [0, 0], + [-1.331, 20.755], + [0.499, 8.061], + [-17.095, 16.887], + [0, 0], + [0.582, 1.289], + [9.144, 12.981], + [4.576, -1.248], + [0, 0], + [17.345, 11.563], + [7.202, 3.563], + [6.114, 23.293], + [0, 0], + [1.498, 0.125] + ], + "o": [ + [-1.497, 0.125], + [0, 0], + [-6.114, 23.334], + [-7.196, 3.578], + [-17.345, 11.563], + [0, 0], + [-4.534, -1.248], + [-9.151, 12.978], + [-0.582, 1.289], + [0, 0], + [17.095, 16.887], + [-0.5, 8.062], + [1.331, 20.755], + [0, 0], + [-3.369, 3.328], + [6.738, 14.392], + [0.832, 1.248], + [0, 0], + [23.293, -6.364], + [6.697, 4.451], + [18.593, 9.234], + [0, 0], + [1.206, 4.533], + [15.804, 1.373], + [1.498, -0.124], + [0, 0], + [6.114, -23.335], + [7.196, -3.578], + [17.345, -11.563], + [0, 0], + [4.534, 1.206], + [9.151, -13.019], + [0.582, -1.289], + [0, 0], + [-17.095, -16.887], + [0.499, -8.062], + [-1.331, -20.756], + [0, 0], + [3.369, -3.328], + [-6.715, -14.39], + [-0.832, -1.248], + [0, 0], + [-23.293, 6.364], + [-6.676, -4.47], + [-18.592, -9.234], + [0, 0], + [-1.207, -4.575], + [-15.804, -1.372] + ], + "v": [ + [-23.81, -269.32], + [-29.508, -263.247], + [-41.529, -217.285], + [-83.04, -167.829], + [-103.838, -155.766], + [-167.436, -144.536], + [-213.314, -157.139], + [-221.425, -155.267], + [-245.259, -114.089], + [-242.805, -106.185], + [-208.905, -72.66], + [-186.86, -12.099], + [-186.86, 12.109], + [-208.905, 72.671], + [-242.805, 106.195], + [-245.259, 114.099], + [-221.425, 155.236], + [-213.314, 157.15], + [-167.477, 144.547], + [-103.838, 155.777], + [-82.999, 167.839], + [-41.529, 217.295], + [-29.508, 263.257], + [-23.81, 269.329], + [23.691, 269.329], + [29.39, 263.257], + [41.411, 217.295], + [82.922, 167.839], + [103.719, 155.777], + [167.317, 144.547], + [213.196, 157.15], + [221.307, 155.277], + [245.141, 114.099], + [242.687, 106.195], + [208.787, 72.671], + [186.742, 12.109], + [186.742, -12.098], + [208.787, -72.66], + [242.687, -106.185], + [245.141, -114.089], + [221.307, -155.225], + [213.196, -157.139], + [167.359, -144.536], + [103.719, -155.766], + [82.88, -167.828], + [41.411, -217.285], + [29.39, -263.247], + [23.691, -269.32] + ], + "c": true + }, + "ix": 2 + }, + "nm": "Path 3", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ind": 3, + "ty": "sh", + "ix": 4, + "ks": { + "a": 0, + "k": { + "i": [ + [-9.816, 0], + [-9.697, -0.846], + [-7.071, -26.828], + [0, 0], + [-5.532, -2.745], + [-8.902, -5.948], + [-2.745, 0.79], + [0, 0], + [-17.802, -25.331], + [-8.236, -17.72], + [19.758, -19.508], + [0, 0], + [-0.416, -6.114], + [0.666, -10.69], + [-2.079, -1.997], + [0, 0], + [13.102, -28.076], + [11.232, -15.979], + [26.787, 7.363], + [0, 0], + [5.117, -3.411], + [9.602, -4.741], + [0.707, -2.745], + [0, 0], + [30.904, -2.663], + [19.401, 1.705], + [7.03, 26.87], + [0, 0], + [5.532, 2.745], + [8.891, 5.969], + [2.746, -0.79], + [0, 0], + [17.802, 25.332], + [8.277, 17.703], + [-19.716, 19.508], + [0, 0], + [0.416, 6.114], + [-0.666, 10.693], + [2.08, 1.997], + [0, 0], + [-13.102, 28.076], + [-11.242, 15.972], + [-26.787, -7.363], + [0, 0], + [-5.116, 3.411], + [-9.608, 4.742], + [-0.707, 2.745], + [0, 0], + [-30.905, 2.704] + ], + "o": [ + [9.733, 0.014], + [30.904, 2.662], + [0, 0], + [0.749, 2.745], + [9.609, 4.742], + [5.116, 3.411], + [0, 0], + [26.787, -7.321], + [11.231, 16.014], + [13.102, 28.076], + [0, 0], + [-2.038, 1.997], + [0.666, 10.69], + [-0.416, 6.114], + [0, 0], + [19.758, 19.508], + [-8.252, 17.703], + [-17.802, 25.373], + [0, 0], + [-2.787, -0.79], + [-8.902, 5.952], + [-5.532, 2.745], + [0, 0], + [-6.987, 26.87], + [-19.402, 1.705], + [-30.905, -2.663], + [0, 0], + [-0.748, -2.745], + [-9.611, -4.723], + [-5.116, -3.411], + [0, 0], + [-26.786, 7.321], + [-11.208, -16.008], + [-13.102, -28.076], + [0, 0], + [2.08, -1.997], + [-0.666, -10.693], + [0.416, -6.114], + [0, 0], + [-19.716, -19.508], + [8.241, -17.709], + [17.802, -25.373], + [0, 0], + [2.787, 0.79], + [8.901, -5.948], + [5.532, -2.745], + [0, 0], + [6.988, -26.87], + [9.608, -0.832] + ], + "v": [ + [-0.059, -332.751], + [29.099, -331.462], + [89.785, -279.095], + [101.764, -233.049], + [110.582, -223.733], + [138.368, -207.676], + [150.804, -204.723], + [196.683, -217.327], + [272.385, -191.123], + [301.668, -140.459], + [286.527, -61.805], + [252.669, -28.28], + [249.009, -16.051], + [249.009, 16.061], + [252.669, 28.289], + [286.527, 61.815], + [301.668, 140.47], + [272.385, 191.09], + [196.683, 217.295], + [150.846, 204.734], + [138.367, 207.687], + [110.582, 223.743], + [101.806, 233.059], + [89.743, 279.063], + [29.099, 331.473], + [-29.217, 331.473], + [-89.862, 279.063], + [-101.883, 233.059], + [-110.701, 223.743], + [-138.486, 207.687], + [-150.923, 204.734], + [-196.802, 217.336], + [-272.504, 191.132], + [-301.786, 140.47], + [-286.687, 61.815], + [-252.788, 28.289], + [-249.127, 16.061], + [-249.127, -16.051], + [-252.788, -28.28], + [-286.687, -61.805], + [-301.786, -140.459], + [-272.504, -191.08], + [-196.801, -217.285], + [-150.964, -204.723], + [-138.486, -207.676], + [-110.701, -223.733], + [-101.924, -233.049], + [-89.862, -279.053], + [-29.217, -331.504] + ], + "c": true + }, + "ix": 2 + }, + "nm": "Path 4", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ty": "mm", + "mm": 1, + "nm": "Merge Paths 1", + "mn": "ADBE Vector Filter - Merge", + "hd": false + }, + { + "ty": "fl", + "c": { + "a": 0, + "k": [0.898460657456, 0.889815326765, 0.896223060758, 1], + "ix": 4 + }, + "o": { "a": 0, "k": 100, "ix": 5 }, + "r": 1, + "bm": 0, + "nm": "Fill 1", + "mn": "ADBE Vector Graphic - Fill", + "hd": false + }, + { + "ty": "tr", + "p": { "a": 0, "k": [308.077, 333.249], "ix": 2 }, + "a": { "a": 0, "k": [0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100], "ix": 3 }, + "r": { "a": 0, "k": 0, "ix": 6 }, + "o": { "a": 0, "k": 100, "ix": 7 }, + "sk": { "a": 0, "k": 0, "ix": 4 }, + "sa": { "a": 0, "k": 0, "ix": 5 }, + "nm": "Transform" + } + ], + "nm": "Group 1", + "np": 8, + "cix": 2, + "bm": 0, + "ix": 1, + "mn": "ADBE Vector Group", + "hd": false + } + ], + "ip": 0, + "op": 120, + "st": 0, + "bm": 0 + } + ], + "markers": [] +} diff --git a/src/renderer/declaration.d.ts b/src/renderer/declaration.d.ts index cceed299..393717ba 100644 --- a/src/renderer/declaration.d.ts +++ b/src/renderer/declaration.d.ts @@ -22,7 +22,8 @@ declare global { repackId: number, objectID: string, title: string, - shop: GameShop + shop: GameShop, + downloadPath: string ) => Promise; cancelGameDownload: (gameId: number) => Promise; pauseGameDownload: (gameId: number) => Promise; diff --git a/src/renderer/hooks/use-download.ts b/src/renderer/hooks/use-download.ts index 522dd2c2..27f90e8d 100644 --- a/src/renderer/hooks/use-download.ts +++ b/src/renderer/hooks/use-download.ts @@ -28,10 +28,11 @@ export function useDownload() { repackId: number, objectID: string, title: string, - shop: GameShop + shop: GameShop, + downloadPath: string ) => window.electron - .startGameDownload(repackId, objectID, title, shop) + .startGameDownload(repackId, objectID, title, shop, downloadPath) .then((game) => { dispatch(clearDownload()); updateLibrary(); diff --git a/src/renderer/pages/game-details/game-details.tsx b/src/renderer/pages/game-details/game-details.tsx index 12d9d940..88e91ba2 100644 --- a/src/renderer/pages/game-details/game-details.tsx +++ b/src/renderer/pages/game-details/game-details.tsx @@ -138,12 +138,16 @@ export function GameDetails() { }; }, [game?.id, isGamePlaying, getGame]); - const handleStartDownload = async (repackId: number) => { + const handleStartDownload = async ( + repackId: number, + downloadPath: string + ) => { return startDownload( repackId, gameDetails.objectID, gameDetails.name, - shop as GameShop + shop as GameShop, + downloadPath ).then(() => { getGame(); setShowRepacksModal(false); diff --git a/src/renderer/pages/game-details/repacks-modal.tsx b/src/renderer/pages/game-details/repacks-modal.tsx index b3917b23..bb47060e 100644 --- a/src/renderer/pages/game-details/repacks-modal.tsx +++ b/src/renderer/pages/game-details/repacks-modal.tsx @@ -10,11 +10,12 @@ import type { DiskSpace } from "check-disk-space"; import { format } from "date-fns"; import { SPACING_UNIT } from "@renderer/theme.css"; import { formatBytes } from "@renderer/utils"; +import { SelectFolderModal } from "./select-folder-modal"; export interface RepacksModalProps { visible: boolean; gameDetails: ShopDetails; - startDownload: (repackId: number) => Promise; + startDownload: (repackId: number, downloadPath: string) => Promise; onClose: () => void; } @@ -24,9 +25,10 @@ export function RepacksModal({ startDownload, onClose, }: RepacksModalProps) { - const [downloadStarting, setDownloadStarting] = useState(false); + const [openSelectFolderModal, setOpenSelectFolderModal] = useState(false); const [diskFreeSpace, setDiskFreeSpace] = useState(null); const [filteredRepacks, setFilteredRepacks] = useState([]); + const [repack, setRepack] = useState(null); const { t } = useTranslation("game_details"); @@ -45,10 +47,8 @@ export function RepacksModal({ }, [visible]); const handleRepackClick = (repack: GameRepack) => { - setDownloadStarting(true); - startDownload(repack.id).finally(() => { - setDownloadStarting(false); - }); + setRepack(repack); + setOpenSelectFolderModal(true); }; const handleFilter: React.ChangeEventHandler = (event) => { @@ -70,6 +70,13 @@ export function RepacksModal({ })} onClose={onClose} > + setOpenSelectFolderModal(false)} + gameDetails={gameDetails} + startDownload={startDownload} + repack={repack} + />
@@ -80,7 +87,6 @@ export function RepacksModal({ key={repack.id} theme="dark" onClick={() => handleRepackClick(repack)} - disabled={downloadStarting} className={styles.repackButton} >

{repack.title}

diff --git a/src/renderer/pages/game-details/select-folder-modal.css.tsx b/src/renderer/pages/game-details/select-folder-modal.css.tsx new file mode 100644 index 00000000..7d32bccc --- /dev/null +++ b/src/renderer/pages/game-details/select-folder-modal.css.tsx @@ -0,0 +1,19 @@ +import { style } from "@vanilla-extract/css"; +import { SPACING_UNIT, vars } from "@renderer/theme.css"; + +export const container = style({ + display: "flex", + flexDirection: "column", + gap: `${SPACING_UNIT * 2}px`, + width: "100%", +}); + +export const downloadsPathField = style({ + display: "flex", + gap: `${SPACING_UNIT * 2}px`, +}); + +export const hintText = style({ + fontSize: 12, + color: vars.color.bodyText, +}); diff --git a/src/renderer/pages/game-details/select-folder-modal.tsx b/src/renderer/pages/game-details/select-folder-modal.tsx new file mode 100644 index 00000000..4ba06ece --- /dev/null +++ b/src/renderer/pages/game-details/select-folder-modal.tsx @@ -0,0 +1,103 @@ +import { Button, Modal, TextField } from "@renderer/components"; +import { GameRepack, ShopDetails } from "@types"; +import { useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; + +import * as styles from "./select-folder-modal.css"; +import { Link } from "react-router-dom"; + +export interface SelectFolderModalProps { + visible: boolean; + gameDetails: ShopDetails; + onClose: () => void; + startDownload: (repackId: number, downloadPath: string) => Promise; + repack: GameRepack; +} + +export function SelectFolderModal({ + visible, + gameDetails, + onClose, + startDownload, + repack, +}: SelectFolderModalProps) { + const { t } = useTranslation("game_details"); + + const [selectedPath, setSelectedPath] = useState({ + downloadsPath: "", + }); + const [downloadStarting, setDownloadStarting] = useState(false); + + useEffect(() => { + Promise.all([ + window.electron.getDefaultDownloadsPath(), + window.electron.getUserPreferences(), + ]).then(([path, userPreferences]) => { + setSelectedPath({ + downloadsPath: userPreferences?.downloadsPath || path, + }); + }); + }, []); + + const handleChooseDownloadsPath = async () => { + const { filePaths } = await window.electron.showOpenDialog({ + defaultPath: selectedPath.downloadsPath, + properties: ["openDirectory"], + }); + + if (filePaths && filePaths.length > 0) { + const path = filePaths[0]; + setSelectedPath({ downloadsPath: path }); + } + }; + + const handleStartClick = () => { + setDownloadStarting(true); + startDownload(repack.id, selectedPath.downloadsPath).finally(() => { + setDownloadStarting(false); + }); + }; + + return ( + +
+
+ + + +
+

+ {t("select_folder_hint")}{" "} + + {t("hydra_settings")} + +

+ +
+
+ ); +} From 7a3f0ef9e27f9fb29d08948508660fca87a2720a Mon Sep 17 00:00:00 2001 From: Hydra Date: Sat, 20 Apr 2024 15:54:08 -0300 Subject: [PATCH 002/140] feat: add a modal to select game installation folder (pt and en translation) --- forge.config.ts | 6 +- src/locales/en/translation.json | 8 +- src/locales/pt/translation.json | 8 +- .../events/library/add-game-to-library.ts | 2 +- .../events/torrenting/start-game-download.ts | 6 +- src/preload.ts | 13 +- src/renderer/assets/lottie/settings.json | 1055 ++++++++++++++++- src/renderer/declaration.d.ts | 3 +- src/renderer/hooks/use-download.ts | 5 +- .../pages/game-details/game-details.tsx | 8 +- .../pages/game-details/repacks-modal.tsx | 20 +- .../game-details/select-folder-modal.css.tsx | 19 + .../game-details/select-folder-modal.tsx | 103 ++ 13 files changed, 1232 insertions(+), 24 deletions(-) create mode 100644 src/renderer/pages/game-details/select-folder-modal.css.tsx create mode 100644 src/renderer/pages/game-details/select-folder-modal.tsx diff --git a/forge.config.ts b/forge.config.ts index 21718764..94cfac57 100644 --- a/forge.config.ts +++ b/forge.config.ts @@ -20,7 +20,7 @@ const linuxPkgConfig = { icon: "images/icon.png", genericName: "Games Launcher", name: "hydra-launcher", - productName: "Hydra" + productName: "Hydra", }; const config: ForgeConfig = { @@ -50,10 +50,10 @@ const config: ForgeConfig = { }), new MakerZIP({}, ["darwin", "linux"]), new MakerRpm({ - options: linuxPkgConfig + options: linuxPkgConfig, }), new MakerDeb({ - options: linuxPkgConfig + options: linuxPkgConfig, }), ], publishers: [ diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index f59f1e87..a9fcb19d 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -77,7 +77,13 @@ "play": "Play", "deleting": "Deleting installer…", "close": "Close", - "playing_now": "Playing now" + "playing_now": "Playing now", + "change": "Change", + "select_folder_description": "Select the folder where the game will be installed", + "downloads_path": "Downloads path", + "select_folder_hint": "To change the default folder, access the", + "hydra_settings": "Hydra settings", + "download_now": "Download now" }, "activation": { "title": "Activate Hydra", diff --git a/src/locales/pt/translation.json b/src/locales/pt/translation.json index 145163b4..c2d24840 100644 --- a/src/locales/pt/translation.json +++ b/src/locales/pt/translation.json @@ -73,7 +73,13 @@ "not_played_yet": "Você ainda não jogou {{title}}", "close": "Fechar", "deleting": "Excluindo instalador…", - "playing_now": "Jogando agora" + "playing_now": "Jogando agora", + "change": "Mudar", + "select_folder_description": "Selecione a pasta em que o jogo será baixado", + "downloads_path": "Diretório do download", + "select_folder_hint": "Para trocar a pasta padrão, acesse as ", + "hydra_settings": "Configurações do Hydra", + "download_now": "Baixe agora" }, "activation": { "title": "Ativação", diff --git a/src/main/events/library/add-game-to-library.ts b/src/main/events/library/add-game-to-library.ts index 8680b29a..12e4c8bf 100644 --- a/src/main/events/library/add-game-to-library.ts +++ b/src/main/events/library/add-game-to-library.ts @@ -10,7 +10,7 @@ const addGameToLibrary = async ( _event: Electron.IpcMainInvokeEvent, objectID: string, title: string, - gameShop: GameShop, + gameShop: GameShop ) => { const iconUrl = await getImageBase64(await getSteamGameIconUrl(objectID)); diff --git a/src/main/events/torrenting/start-game-download.ts b/src/main/events/torrenting/start-game-download.ts index 570fd2ec..f661a956 100644 --- a/src/main/events/torrenting/start-game-download.ts +++ b/src/main/events/torrenting/start-game-download.ts @@ -5,7 +5,6 @@ import { GameStatus } from "@main/constants"; import { registerEvent } from "../register-event"; import type { GameShop } from "@types"; -import { getDownloadsPath } from "../helpers/get-downloads-path"; import { getImageBase64 } from "@main/helpers"; import { In } from "typeorm"; @@ -14,7 +13,8 @@ const startGameDownload = async ( repackId: number, objectID: string, title: string, - gameShop: GameShop + gameShop: GameShop, + downloadPath: string ) => { const [game, repack] = await Promise.all([ gameRepository.findOne({ @@ -37,7 +37,7 @@ const startGameDownload = async ( writePipe.write({ action: "pause" }); - const downloadsPath = game?.downloadPath ?? (await getDownloadsPath()); + const downloadsPath = game?.downloadPath ?? downloadPath; await gameRepository.update( { diff --git a/src/preload.ts b/src/preload.ts index 93acde24..7ee37d0b 100644 --- a/src/preload.ts +++ b/src/preload.ts @@ -15,8 +15,17 @@ contextBridge.exposeInMainWorld("electron", { repackId: number, objectID: string, title: string, - shop: GameShop - ) => ipcRenderer.invoke("startGameDownload", repackId, objectID, title, shop), + shop: GameShop, + downloadPath: string + ) => + ipcRenderer.invoke( + "startGameDownload", + repackId, + objectID, + title, + shop, + downloadPath + ), cancelGameDownload: (gameId: number) => ipcRenderer.invoke("cancelGameDownload", gameId), pauseGameDownload: (gameId: number) => diff --git a/src/renderer/assets/lottie/settings.json b/src/renderer/assets/lottie/settings.json index 4d37e53a..92fa645e 100644 --- a/src/renderer/assets/lottie/settings.json +++ b/src/renderer/assets/lottie/settings.json @@ -1 +1,1054 @@ -{"v":"4.8.0","meta":{"g":"LottieFiles AE 3.5.6","a":"","k":"","d":"","tc":""},"fr":60,"ip":0,"op":120,"w":900,"h":900,"nm":"Pre-comp 1","ddd":0,"assets":[{"id":"comp_0","layers":[{"ddd":0,"ind":1,"ty":4,"nm":"estrela Outlines 2","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.933],"y":[0]},"t":0,"s":[0]},{"t":60,"s":[180]}],"ix":10},"p":{"a":0,"k":[450,450,0],"ix":2},"a":{"a":0,"k":[308.5,333,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.011,34.469],[34.47,-0.012],[-0.011,-34.469],[-34.47,0.011]],"o":[[-0.012,-34.47],[-34.469,0.011],[0.012,34.47],[34.469,-0.012]],"v":[[62.333,0.005],[-0.101,-62.387],[-62.493,0.047],[-0.059,62.439]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,-68.917],[68.916,0],[0,68.916],[-68.916,0]],"o":[[0,68.916],[-68.916,0],[0,-68.917],[68.916,0]],"v":[[124.725,0.005],[-0.059,124.789],[-124.843,0.005],[-0.059,-124.779]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[15.804,-1.372],[1.206,-4.575],[0,0],[18.676,-9.234],[6.656,-4.451],[23.252,6.364],[0,0],[0.832,-1.206],[6.697,-14.392],[-3.327,-3.328],[0,0],[1.331,-20.755],[-0.499,-8.062],[17.095,-16.887],[0,0],[-0.582,-1.289],[-9.151,-12.977],[-4.575,1.248],[0,0],[-17.345,-11.563],[-7.196,-3.578],[-6.114,-23.293],[0,0],[-1.497,-0.124],[-15.804,1.373],[-1.207,4.575],[0,0],[-18.676,9.234],[-6.655,4.451],[-23.251,-6.364],[0,0],[-0.832,1.206],[-6.739,14.392],[3.327,3.328],[0,0],[-1.331,20.755],[0.499,8.061],[-17.095,16.887],[0,0],[0.582,1.289],[9.144,12.981],[4.576,-1.248],[0,0],[17.345,11.563],[7.202,3.563],[6.114,23.293],[0,0],[1.498,0.125]],"o":[[-1.497,0.125],[0,0],[-6.114,23.334],[-7.196,3.578],[-17.345,11.563],[0,0],[-4.534,-1.248],[-9.151,12.978],[-0.582,1.289],[0,0],[17.095,16.887],[-0.5,8.062],[1.331,20.755],[0,0],[-3.369,3.328],[6.738,14.392],[0.832,1.248],[0,0],[23.293,-6.364],[6.697,4.451],[18.593,9.234],[0,0],[1.206,4.533],[15.804,1.373],[1.498,-0.124],[0,0],[6.114,-23.335],[7.196,-3.578],[17.345,-11.563],[0,0],[4.534,1.206],[9.151,-13.019],[0.582,-1.289],[0,0],[-17.095,-16.887],[0.499,-8.062],[-1.331,-20.756],[0,0],[3.369,-3.328],[-6.715,-14.39],[-0.832,-1.248],[0,0],[-23.293,6.364],[-6.676,-4.47],[-18.592,-9.234],[0,0],[-1.207,-4.575],[-15.804,-1.372]],"v":[[-23.81,-269.32],[-29.508,-263.247],[-41.529,-217.285],[-83.04,-167.829],[-103.838,-155.766],[-167.436,-144.536],[-213.314,-157.139],[-221.425,-155.267],[-245.259,-114.089],[-242.805,-106.185],[-208.905,-72.66],[-186.86,-12.099],[-186.86,12.109],[-208.905,72.671],[-242.805,106.195],[-245.259,114.099],[-221.425,155.236],[-213.314,157.15],[-167.477,144.547],[-103.838,155.777],[-82.999,167.839],[-41.529,217.295],[-29.508,263.257],[-23.81,269.329],[23.691,269.329],[29.39,263.257],[41.411,217.295],[82.922,167.839],[103.719,155.777],[167.317,144.547],[213.196,157.15],[221.307,155.277],[245.141,114.099],[242.687,106.195],[208.787,72.671],[186.742,12.109],[186.742,-12.098],[208.787,-72.66],[242.687,-106.185],[245.141,-114.089],[221.307,-155.225],[213.196,-157.139],[167.359,-144.536],[103.719,-155.766],[82.88,-167.828],[41.411,-217.285],[29.39,-263.247],[23.691,-269.32]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[-9.816,0],[-9.697,-0.846],[-7.071,-26.828],[0,0],[-5.532,-2.745],[-8.902,-5.948],[-2.745,0.79],[0,0],[-17.802,-25.331],[-8.236,-17.72],[19.758,-19.508],[0,0],[-0.416,-6.114],[0.666,-10.69],[-2.079,-1.997],[0,0],[13.102,-28.076],[11.232,-15.979],[26.787,7.363],[0,0],[5.117,-3.411],[9.602,-4.741],[0.707,-2.745],[0,0],[30.904,-2.663],[19.401,1.705],[7.03,26.87],[0,0],[5.532,2.745],[8.891,5.969],[2.746,-0.79],[0,0],[17.802,25.332],[8.277,17.703],[-19.716,19.508],[0,0],[0.416,6.114],[-0.666,10.693],[2.08,1.997],[0,0],[-13.102,28.076],[-11.242,15.972],[-26.787,-7.363],[0,0],[-5.116,3.411],[-9.608,4.742],[-0.707,2.745],[0,0],[-30.905,2.704]],"o":[[9.733,0.014],[30.904,2.662],[0,0],[0.749,2.745],[9.609,4.742],[5.116,3.411],[0,0],[26.787,-7.321],[11.231,16.014],[13.102,28.076],[0,0],[-2.038,1.997],[0.666,10.69],[-0.416,6.114],[0,0],[19.758,19.508],[-8.252,17.703],[-17.802,25.373],[0,0],[-2.787,-0.79],[-8.902,5.952],[-5.532,2.745],[0,0],[-6.987,26.87],[-19.402,1.705],[-30.905,-2.663],[0,0],[-0.748,-2.745],[-9.611,-4.723],[-5.116,-3.411],[0,0],[-26.786,7.321],[-11.208,-16.008],[-13.102,-28.076],[0,0],[2.08,-1.997],[-0.666,-10.693],[0.416,-6.114],[0,0],[-19.716,-19.508],[8.241,-17.709],[17.802,-25.373],[0,0],[2.787,0.79],[8.901,-5.948],[5.532,-2.745],[0,0],[6.988,-26.87],[9.608,-0.832]],"v":[[-0.059,-332.751],[29.099,-331.462],[89.785,-279.095],[101.764,-233.049],[110.582,-223.733],[138.368,-207.676],[150.804,-204.723],[196.683,-217.327],[272.385,-191.123],[301.668,-140.459],[286.527,-61.805],[252.669,-28.28],[249.009,-16.051],[249.009,16.061],[252.669,28.289],[286.527,61.815],[301.668,140.47],[272.385,191.09],[196.683,217.295],[150.846,204.734],[138.367,207.687],[110.582,223.743],[101.806,233.059],[89.743,279.063],[29.099,331.473],[-29.217,331.473],[-89.862,279.063],[-101.883,233.059],[-110.701,223.743],[-138.486,207.687],[-150.923,204.734],[-196.802,217.336],[-272.504,191.132],[-301.786,140.47],[-286.687,61.815],[-252.788,28.289],[-249.127,16.061],[-249.127,-16.051],[-252.788,-28.28],[-286.687,-61.805],[-301.786,-140.459],[-272.504,-191.08],[-196.801,-217.285],[-150.964,-204.723],[-138.486,-207.676],[-110.701,-223.733],[-101.924,-233.049],[-89.862,-279.053],[-29.217,-331.504]],"c":true},"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.898460657456,0.889815326765,0.896223060758,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[308.077,333.249],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":8,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"estrela Outlines 2 Comp 1","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[450,450,0],"ix":2},"a":{"a":0,"k":[450,450,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[1,1,0.333],"y":[0,0,0]},"t":0,"s":[100,100,100]},{"i":{"x":[0,0,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":30,"s":[80,80,100]},{"t":60,"s":[100,100,100]}],"ix":6}},"ao":0,"hasMask":true,"masksProperties":[{"inv":false,"mode":"a","pt":{"a":0,"k":{"i":[[89.47,0],[0,-89.47],[-89.47,0],[0,89.47]],"o":[[-89.47,0],[0,89.47],[89.47,0],[0,-89.47]],"v":[[446,286],[284,448],[446,610],[608,448]],"c":true},"ix":1},"o":{"a":0,"k":100,"ix":3},"x":{"a":0,"k":0,"ix":4},"nm":"Mask 1"}],"w":900,"h":900,"ip":0,"op":120,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":"estrela Outlines","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.84],"y":[-1.753]},"o":{"x":[0],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.361],"y":[1]},"o":{"x":[0],"y":[0]},"t":28,"s":[15]},{"t":60,"s":[180]}],"ix":10},"p":{"a":0,"k":[450,450,0],"ix":2},"a":{"a":0,"k":[308.5,333,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0.011,34.469],[34.47,-0.012],[-0.011,-34.469],[-34.47,0.011]],"o":[[-0.012,-34.47],[-34.469,0.011],[0.012,34.47],[34.469,-0.012]],"v":[[62.333,0.005],[-0.101,-62.387],[-62.493,0.047],[-0.059,62.439]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ind":1,"ty":"sh","ix":2,"ks":{"a":0,"k":{"i":[[0,-68.917],[68.916,0],[0,68.916],[-68.916,0]],"o":[[0,68.916],[-68.916,0],[0,-68.917],[68.916,0]],"v":[[124.725,0.005],[-0.059,124.789],[-124.843,0.005],[-0.059,-124.779]],"c":true},"ix":2},"nm":"Path 2","mn":"ADBE Vector Shape - Group","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":0,"k":{"i":[[15.804,-1.372],[1.206,-4.575],[0,0],[18.676,-9.234],[6.656,-4.451],[23.252,6.364],[0,0],[0.832,-1.206],[6.697,-14.392],[-3.327,-3.328],[0,0],[1.331,-20.755],[-0.499,-8.062],[17.095,-16.887],[0,0],[-0.582,-1.289],[-9.151,-12.977],[-4.575,1.248],[0,0],[-17.345,-11.563],[-7.196,-3.578],[-6.114,-23.293],[0,0],[-1.497,-0.124],[-15.804,1.373],[-1.207,4.575],[0,0],[-18.676,9.234],[-6.655,4.451],[-23.251,-6.364],[0,0],[-0.832,1.206],[-6.739,14.392],[3.327,3.328],[0,0],[-1.331,20.755],[0.499,8.061],[-17.095,16.887],[0,0],[0.582,1.289],[9.144,12.981],[4.576,-1.248],[0,0],[17.345,11.563],[7.202,3.563],[6.114,23.293],[0,0],[1.498,0.125]],"o":[[-1.497,0.125],[0,0],[-6.114,23.334],[-7.196,3.578],[-17.345,11.563],[0,0],[-4.534,-1.248],[-9.151,12.978],[-0.582,1.289],[0,0],[17.095,16.887],[-0.5,8.062],[1.331,20.755],[0,0],[-3.369,3.328],[6.738,14.392],[0.832,1.248],[0,0],[23.293,-6.364],[6.697,4.451],[18.593,9.234],[0,0],[1.206,4.533],[15.804,1.373],[1.498,-0.124],[0,0],[6.114,-23.335],[7.196,-3.578],[17.345,-11.563],[0,0],[4.534,1.206],[9.151,-13.019],[0.582,-1.289],[0,0],[-17.095,-16.887],[0.499,-8.062],[-1.331,-20.756],[0,0],[3.369,-3.328],[-6.715,-14.39],[-0.832,-1.248],[0,0],[-23.293,6.364],[-6.676,-4.47],[-18.592,-9.234],[0,0],[-1.207,-4.575],[-15.804,-1.372]],"v":[[-23.81,-269.32],[-29.508,-263.247],[-41.529,-217.285],[-83.04,-167.829],[-103.838,-155.766],[-167.436,-144.536],[-213.314,-157.139],[-221.425,-155.267],[-245.259,-114.089],[-242.805,-106.185],[-208.905,-72.66],[-186.86,-12.099],[-186.86,12.109],[-208.905,72.671],[-242.805,106.195],[-245.259,114.099],[-221.425,155.236],[-213.314,157.15],[-167.477,144.547],[-103.838,155.777],[-82.999,167.839],[-41.529,217.295],[-29.508,263.257],[-23.81,269.329],[23.691,269.329],[29.39,263.257],[41.411,217.295],[82.922,167.839],[103.719,155.777],[167.317,144.547],[213.196,157.15],[221.307,155.277],[245.141,114.099],[242.687,106.195],[208.787,72.671],[186.742,12.109],[186.742,-12.098],[208.787,-72.66],[242.687,-106.185],[245.141,-114.089],[221.307,-155.225],[213.196,-157.139],[167.359,-144.536],[103.719,-155.766],[82.88,-167.828],[41.411,-217.285],[29.39,-263.247],[23.691,-269.32]],"c":true},"ix":2},"nm":"Path 3","mn":"ADBE Vector Shape - Group","hd":false},{"ind":3,"ty":"sh","ix":4,"ks":{"a":0,"k":{"i":[[-9.816,0],[-9.697,-0.846],[-7.071,-26.828],[0,0],[-5.532,-2.745],[-8.902,-5.948],[-2.745,0.79],[0,0],[-17.802,-25.331],[-8.236,-17.72],[19.758,-19.508],[0,0],[-0.416,-6.114],[0.666,-10.69],[-2.079,-1.997],[0,0],[13.102,-28.076],[11.232,-15.979],[26.787,7.363],[0,0],[5.117,-3.411],[9.602,-4.741],[0.707,-2.745],[0,0],[30.904,-2.663],[19.401,1.705],[7.03,26.87],[0,0],[5.532,2.745],[8.891,5.969],[2.746,-0.79],[0,0],[17.802,25.332],[8.277,17.703],[-19.716,19.508],[0,0],[0.416,6.114],[-0.666,10.693],[2.08,1.997],[0,0],[-13.102,28.076],[-11.242,15.972],[-26.787,-7.363],[0,0],[-5.116,3.411],[-9.608,4.742],[-0.707,2.745],[0,0],[-30.905,2.704]],"o":[[9.733,0.014],[30.904,2.662],[0,0],[0.749,2.745],[9.609,4.742],[5.116,3.411],[0,0],[26.787,-7.321],[11.231,16.014],[13.102,28.076],[0,0],[-2.038,1.997],[0.666,10.69],[-0.416,6.114],[0,0],[19.758,19.508],[-8.252,17.703],[-17.802,25.373],[0,0],[-2.787,-0.79],[-8.902,5.952],[-5.532,2.745],[0,0],[-6.987,26.87],[-19.402,1.705],[-30.905,-2.663],[0,0],[-0.748,-2.745],[-9.611,-4.723],[-5.116,-3.411],[0,0],[-26.786,7.321],[-11.208,-16.008],[-13.102,-28.076],[0,0],[2.08,-1.997],[-0.666,-10.693],[0.416,-6.114],[0,0],[-19.716,-19.508],[8.241,-17.709],[17.802,-25.373],[0,0],[2.787,0.79],[8.901,-5.948],[5.532,-2.745],[0,0],[6.988,-26.87],[9.608,-0.832]],"v":[[-0.059,-332.751],[29.099,-331.462],[89.785,-279.095],[101.764,-233.049],[110.582,-223.733],[138.368,-207.676],[150.804,-204.723],[196.683,-217.327],[272.385,-191.123],[301.668,-140.459],[286.527,-61.805],[252.669,-28.28],[249.009,-16.051],[249.009,16.061],[252.669,28.289],[286.527,61.815],[301.668,140.47],[272.385,191.09],[196.683,217.295],[150.846,204.734],[138.367,207.687],[110.582,223.743],[101.806,233.059],[89.743,279.063],[29.099,331.473],[-29.217,331.473],[-89.862,279.063],[-101.883,233.059],[-110.701,223.743],[-138.486,207.687],[-150.923,204.734],[-196.802,217.336],[-272.504,191.132],[-301.786,140.47],[-286.687,61.815],[-252.788,28.289],[-249.127,16.061],[-249.127,-16.051],[-252.788,-28.28],[-286.687,-61.805],[-301.786,-140.459],[-272.504,-191.08],[-196.801,-217.285],[-150.964,-204.723],[-138.486,-207.676],[-110.701,-223.733],[-101.924,-233.049],[-89.862,-279.053],[-29.217,-331.504]],"c":true},"ix":2},"nm":"Path 4","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"mm","mm":1,"nm":"Merge Paths 1","mn":"ADBE Vector Filter - Merge","hd":false},{"ty":"fl","c":{"a":0,"k":[0.898460657456,0.889815326765,0.896223060758,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[308.077,333.249],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":8,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":120,"st":0,"bm":0}],"markers":[]} \ No newline at end of file +{ + "v": "4.8.0", + "meta": { "g": "LottieFiles AE 3.5.6", "a": "", "k": "", "d": "", "tc": "" }, + "fr": 60, + "ip": 0, + "op": 120, + "w": 900, + "h": 900, + "nm": "Pre-comp 1", + "ddd": 0, + "assets": [ + { + "id": "comp_0", + "layers": [ + { + "ddd": 0, + "ind": 1, + "ty": 4, + "nm": "estrela Outlines 2", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100, "ix": 11 }, + "r": { + "a": 1, + "k": [ + { + "i": { "x": [0.667], "y": [1] }, + "o": { "x": [0.933], "y": [0] }, + "t": 0, + "s": [0] + }, + { "t": 60, "s": [180] } + ], + "ix": 10 + }, + "p": { "a": 0, "k": [450, 450, 0], "ix": 2 }, + "a": { "a": 0, "k": [308.5, 333, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100, 100], "ix": 6 } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ix": 1, + "ks": { + "a": 0, + "k": { + "i": [ + [0.011, 34.469], + [34.47, -0.012], + [-0.011, -34.469], + [-34.47, 0.011] + ], + "o": [ + [-0.012, -34.47], + [-34.469, 0.011], + [0.012, 34.47], + [34.469, -0.012] + ], + "v": [ + [62.333, 0.005], + [-0.101, -62.387], + [-62.493, 0.047], + [-0.059, 62.439] + ], + "c": true + }, + "ix": 2 + }, + "nm": "Path 1", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ind": 1, + "ty": "sh", + "ix": 2, + "ks": { + "a": 0, + "k": { + "i": [ + [0, -68.917], + [68.916, 0], + [0, 68.916], + [-68.916, 0] + ], + "o": [ + [0, 68.916], + [-68.916, 0], + [0, -68.917], + [68.916, 0] + ], + "v": [ + [124.725, 0.005], + [-0.059, 124.789], + [-124.843, 0.005], + [-0.059, -124.779] + ], + "c": true + }, + "ix": 2 + }, + "nm": "Path 2", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ind": 2, + "ty": "sh", + "ix": 3, + "ks": { + "a": 0, + "k": { + "i": [ + [15.804, -1.372], + [1.206, -4.575], + [0, 0], + [18.676, -9.234], + [6.656, -4.451], + [23.252, 6.364], + [0, 0], + [0.832, -1.206], + [6.697, -14.392], + [-3.327, -3.328], + [0, 0], + [1.331, -20.755], + [-0.499, -8.062], + [17.095, -16.887], + [0, 0], + [-0.582, -1.289], + [-9.151, -12.977], + [-4.575, 1.248], + [0, 0], + [-17.345, -11.563], + [-7.196, -3.578], + [-6.114, -23.293], + [0, 0], + [-1.497, -0.124], + [-15.804, 1.373], + [-1.207, 4.575], + [0, 0], + [-18.676, 9.234], + [-6.655, 4.451], + [-23.251, -6.364], + [0, 0], + [-0.832, 1.206], + [-6.739, 14.392], + [3.327, 3.328], + [0, 0], + [-1.331, 20.755], + [0.499, 8.061], + [-17.095, 16.887], + [0, 0], + [0.582, 1.289], + [9.144, 12.981], + [4.576, -1.248], + [0, 0], + [17.345, 11.563], + [7.202, 3.563], + [6.114, 23.293], + [0, 0], + [1.498, 0.125] + ], + "o": [ + [-1.497, 0.125], + [0, 0], + [-6.114, 23.334], + [-7.196, 3.578], + [-17.345, 11.563], + [0, 0], + [-4.534, -1.248], + [-9.151, 12.978], + [-0.582, 1.289], + [0, 0], + [17.095, 16.887], + [-0.5, 8.062], + [1.331, 20.755], + [0, 0], + [-3.369, 3.328], + [6.738, 14.392], + [0.832, 1.248], + [0, 0], + [23.293, -6.364], + [6.697, 4.451], + [18.593, 9.234], + [0, 0], + [1.206, 4.533], + [15.804, 1.373], + [1.498, -0.124], + [0, 0], + [6.114, -23.335], + [7.196, -3.578], + [17.345, -11.563], + [0, 0], + [4.534, 1.206], + [9.151, -13.019], + [0.582, -1.289], + [0, 0], + [-17.095, -16.887], + [0.499, -8.062], + [-1.331, -20.756], + [0, 0], + [3.369, -3.328], + [-6.715, -14.39], + [-0.832, -1.248], + [0, 0], + [-23.293, 6.364], + [-6.676, -4.47], + [-18.592, -9.234], + [0, 0], + [-1.207, -4.575], + [-15.804, -1.372] + ], + "v": [ + [-23.81, -269.32], + [-29.508, -263.247], + [-41.529, -217.285], + [-83.04, -167.829], + [-103.838, -155.766], + [-167.436, -144.536], + [-213.314, -157.139], + [-221.425, -155.267], + [-245.259, -114.089], + [-242.805, -106.185], + [-208.905, -72.66], + [-186.86, -12.099], + [-186.86, 12.109], + [-208.905, 72.671], + [-242.805, 106.195], + [-245.259, 114.099], + [-221.425, 155.236], + [-213.314, 157.15], + [-167.477, 144.547], + [-103.838, 155.777], + [-82.999, 167.839], + [-41.529, 217.295], + [-29.508, 263.257], + [-23.81, 269.329], + [23.691, 269.329], + [29.39, 263.257], + [41.411, 217.295], + [82.922, 167.839], + [103.719, 155.777], + [167.317, 144.547], + [213.196, 157.15], + [221.307, 155.277], + [245.141, 114.099], + [242.687, 106.195], + [208.787, 72.671], + [186.742, 12.109], + [186.742, -12.098], + [208.787, -72.66], + [242.687, -106.185], + [245.141, -114.089], + [221.307, -155.225], + [213.196, -157.139], + [167.359, -144.536], + [103.719, -155.766], + [82.88, -167.828], + [41.411, -217.285], + [29.39, -263.247], + [23.691, -269.32] + ], + "c": true + }, + "ix": 2 + }, + "nm": "Path 3", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ind": 3, + "ty": "sh", + "ix": 4, + "ks": { + "a": 0, + "k": { + "i": [ + [-9.816, 0], + [-9.697, -0.846], + [-7.071, -26.828], + [0, 0], + [-5.532, -2.745], + [-8.902, -5.948], + [-2.745, 0.79], + [0, 0], + [-17.802, -25.331], + [-8.236, -17.72], + [19.758, -19.508], + [0, 0], + [-0.416, -6.114], + [0.666, -10.69], + [-2.079, -1.997], + [0, 0], + [13.102, -28.076], + [11.232, -15.979], + [26.787, 7.363], + [0, 0], + [5.117, -3.411], + [9.602, -4.741], + [0.707, -2.745], + [0, 0], + [30.904, -2.663], + [19.401, 1.705], + [7.03, 26.87], + [0, 0], + [5.532, 2.745], + [8.891, 5.969], + [2.746, -0.79], + [0, 0], + [17.802, 25.332], + [8.277, 17.703], + [-19.716, 19.508], + [0, 0], + [0.416, 6.114], + [-0.666, 10.693], + [2.08, 1.997], + [0, 0], + [-13.102, 28.076], + [-11.242, 15.972], + [-26.787, -7.363], + [0, 0], + [-5.116, 3.411], + [-9.608, 4.742], + [-0.707, 2.745], + [0, 0], + [-30.905, 2.704] + ], + "o": [ + [9.733, 0.014], + [30.904, 2.662], + [0, 0], + [0.749, 2.745], + [9.609, 4.742], + [5.116, 3.411], + [0, 0], + [26.787, -7.321], + [11.231, 16.014], + [13.102, 28.076], + [0, 0], + [-2.038, 1.997], + [0.666, 10.69], + [-0.416, 6.114], + [0, 0], + [19.758, 19.508], + [-8.252, 17.703], + [-17.802, 25.373], + [0, 0], + [-2.787, -0.79], + [-8.902, 5.952], + [-5.532, 2.745], + [0, 0], + [-6.987, 26.87], + [-19.402, 1.705], + [-30.905, -2.663], + [0, 0], + [-0.748, -2.745], + [-9.611, -4.723], + [-5.116, -3.411], + [0, 0], + [-26.786, 7.321], + [-11.208, -16.008], + [-13.102, -28.076], + [0, 0], + [2.08, -1.997], + [-0.666, -10.693], + [0.416, -6.114], + [0, 0], + [-19.716, -19.508], + [8.241, -17.709], + [17.802, -25.373], + [0, 0], + [2.787, 0.79], + [8.901, -5.948], + [5.532, -2.745], + [0, 0], + [6.988, -26.87], + [9.608, -0.832] + ], + "v": [ + [-0.059, -332.751], + [29.099, -331.462], + [89.785, -279.095], + [101.764, -233.049], + [110.582, -223.733], + [138.368, -207.676], + [150.804, -204.723], + [196.683, -217.327], + [272.385, -191.123], + [301.668, -140.459], + [286.527, -61.805], + [252.669, -28.28], + [249.009, -16.051], + [249.009, 16.061], + [252.669, 28.289], + [286.527, 61.815], + [301.668, 140.47], + [272.385, 191.09], + [196.683, 217.295], + [150.846, 204.734], + [138.367, 207.687], + [110.582, 223.743], + [101.806, 233.059], + [89.743, 279.063], + [29.099, 331.473], + [-29.217, 331.473], + [-89.862, 279.063], + [-101.883, 233.059], + [-110.701, 223.743], + [-138.486, 207.687], + [-150.923, 204.734], + [-196.802, 217.336], + [-272.504, 191.132], + [-301.786, 140.47], + [-286.687, 61.815], + [-252.788, 28.289], + [-249.127, 16.061], + [-249.127, -16.051], + [-252.788, -28.28], + [-286.687, -61.805], + [-301.786, -140.459], + [-272.504, -191.08], + [-196.801, -217.285], + [-150.964, -204.723], + [-138.486, -207.676], + [-110.701, -223.733], + [-101.924, -233.049], + [-89.862, -279.053], + [-29.217, -331.504] + ], + "c": true + }, + "ix": 2 + }, + "nm": "Path 4", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ty": "mm", + "mm": 1, + "nm": "Merge Paths 1", + "mn": "ADBE Vector Filter - Merge", + "hd": false + }, + { + "ty": "fl", + "c": { + "a": 0, + "k": [0.898460657456, 0.889815326765, 0.896223060758, 1], + "ix": 4 + }, + "o": { "a": 0, "k": 100, "ix": 5 }, + "r": 1, + "bm": 0, + "nm": "Fill 1", + "mn": "ADBE Vector Graphic - Fill", + "hd": false + }, + { + "ty": "tr", + "p": { "a": 0, "k": [308.077, 333.249], "ix": 2 }, + "a": { "a": 0, "k": [0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100], "ix": 3 }, + "r": { "a": 0, "k": 0, "ix": 6 }, + "o": { "a": 0, "k": 100, "ix": 7 }, + "sk": { "a": 0, "k": 0, "ix": 4 }, + "sa": { "a": 0, "k": 0, "ix": 5 }, + "nm": "Transform" + } + ], + "nm": "Group 1", + "np": 8, + "cix": 2, + "bm": 0, + "ix": 1, + "mn": "ADBE Vector Group", + "hd": false + } + ], + "ip": 0, + "op": 120, + "st": 0, + "bm": 0 + } + ] + } + ], + "layers": [ + { + "ddd": 0, + "ind": 1, + "ty": 0, + "nm": "estrela Outlines 2 Comp 1", + "refId": "comp_0", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100, "ix": 11 }, + "r": { "a": 0, "k": 0, "ix": 10 }, + "p": { "a": 0, "k": [450, 450, 0], "ix": 2 }, + "a": { "a": 0, "k": [450, 450, 0], "ix": 1 }, + "s": { + "a": 1, + "k": [ + { + "i": { "x": [0.667, 0.667, 0.667], "y": [1, 1, 1] }, + "o": { "x": [1, 1, 0.333], "y": [0, 0, 0] }, + "t": 0, + "s": [100, 100, 100] + }, + { + "i": { "x": [0, 0, 0.667], "y": [1, 1, 1] }, + "o": { "x": [0.333, 0.333, 0.333], "y": [0, 0, 0] }, + "t": 30, + "s": [80, 80, 100] + }, + { "t": 60, "s": [100, 100, 100] } + ], + "ix": 6 + } + }, + "ao": 0, + "hasMask": true, + "masksProperties": [ + { + "inv": false, + "mode": "a", + "pt": { + "a": 0, + "k": { + "i": [ + [89.47, 0], + [0, -89.47], + [-89.47, 0], + [0, 89.47] + ], + "o": [ + [-89.47, 0], + [0, 89.47], + [89.47, 0], + [0, -89.47] + ], + "v": [ + [446, 286], + [284, 448], + [446, 610], + [608, 448] + ], + "c": true + }, + "ix": 1 + }, + "o": { "a": 0, "k": 100, "ix": 3 }, + "x": { "a": 0, "k": 0, "ix": 4 }, + "nm": "Mask 1" + } + ], + "w": 900, + "h": 900, + "ip": 0, + "op": 120, + "st": 0, + "bm": 0 + }, + { + "ddd": 0, + "ind": 2, + "ty": 4, + "nm": "estrela Outlines", + "sr": 1, + "ks": { + "o": { "a": 0, "k": 100, "ix": 11 }, + "r": { + "a": 1, + "k": [ + { + "i": { "x": [0.84], "y": [-1.753] }, + "o": { "x": [0], "y": [0] }, + "t": 0, + "s": [0] + }, + { + "i": { "x": [0.361], "y": [1] }, + "o": { "x": [0], "y": [0] }, + "t": 28, + "s": [15] + }, + { "t": 60, "s": [180] } + ], + "ix": 10 + }, + "p": { "a": 0, "k": [450, 450, 0], "ix": 2 }, + "a": { "a": 0, "k": [308.5, 333, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100, 100], "ix": 6 } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ix": 1, + "ks": { + "a": 0, + "k": { + "i": [ + [0.011, 34.469], + [34.47, -0.012], + [-0.011, -34.469], + [-34.47, 0.011] + ], + "o": [ + [-0.012, -34.47], + [-34.469, 0.011], + [0.012, 34.47], + [34.469, -0.012] + ], + "v": [ + [62.333, 0.005], + [-0.101, -62.387], + [-62.493, 0.047], + [-0.059, 62.439] + ], + "c": true + }, + "ix": 2 + }, + "nm": "Path 1", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ind": 1, + "ty": "sh", + "ix": 2, + "ks": { + "a": 0, + "k": { + "i": [ + [0, -68.917], + [68.916, 0], + [0, 68.916], + [-68.916, 0] + ], + "o": [ + [0, 68.916], + [-68.916, 0], + [0, -68.917], + [68.916, 0] + ], + "v": [ + [124.725, 0.005], + [-0.059, 124.789], + [-124.843, 0.005], + [-0.059, -124.779] + ], + "c": true + }, + "ix": 2 + }, + "nm": "Path 2", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ind": 2, + "ty": "sh", + "ix": 3, + "ks": { + "a": 0, + "k": { + "i": [ + [15.804, -1.372], + [1.206, -4.575], + [0, 0], + [18.676, -9.234], + [6.656, -4.451], + [23.252, 6.364], + [0, 0], + [0.832, -1.206], + [6.697, -14.392], + [-3.327, -3.328], + [0, 0], + [1.331, -20.755], + [-0.499, -8.062], + [17.095, -16.887], + [0, 0], + [-0.582, -1.289], + [-9.151, -12.977], + [-4.575, 1.248], + [0, 0], + [-17.345, -11.563], + [-7.196, -3.578], + [-6.114, -23.293], + [0, 0], + [-1.497, -0.124], + [-15.804, 1.373], + [-1.207, 4.575], + [0, 0], + [-18.676, 9.234], + [-6.655, 4.451], + [-23.251, -6.364], + [0, 0], + [-0.832, 1.206], + [-6.739, 14.392], + [3.327, 3.328], + [0, 0], + [-1.331, 20.755], + [0.499, 8.061], + [-17.095, 16.887], + [0, 0], + [0.582, 1.289], + [9.144, 12.981], + [4.576, -1.248], + [0, 0], + [17.345, 11.563], + [7.202, 3.563], + [6.114, 23.293], + [0, 0], + [1.498, 0.125] + ], + "o": [ + [-1.497, 0.125], + [0, 0], + [-6.114, 23.334], + [-7.196, 3.578], + [-17.345, 11.563], + [0, 0], + [-4.534, -1.248], + [-9.151, 12.978], + [-0.582, 1.289], + [0, 0], + [17.095, 16.887], + [-0.5, 8.062], + [1.331, 20.755], + [0, 0], + [-3.369, 3.328], + [6.738, 14.392], + [0.832, 1.248], + [0, 0], + [23.293, -6.364], + [6.697, 4.451], + [18.593, 9.234], + [0, 0], + [1.206, 4.533], + [15.804, 1.373], + [1.498, -0.124], + [0, 0], + [6.114, -23.335], + [7.196, -3.578], + [17.345, -11.563], + [0, 0], + [4.534, 1.206], + [9.151, -13.019], + [0.582, -1.289], + [0, 0], + [-17.095, -16.887], + [0.499, -8.062], + [-1.331, -20.756], + [0, 0], + [3.369, -3.328], + [-6.715, -14.39], + [-0.832, -1.248], + [0, 0], + [-23.293, 6.364], + [-6.676, -4.47], + [-18.592, -9.234], + [0, 0], + [-1.207, -4.575], + [-15.804, -1.372] + ], + "v": [ + [-23.81, -269.32], + [-29.508, -263.247], + [-41.529, -217.285], + [-83.04, -167.829], + [-103.838, -155.766], + [-167.436, -144.536], + [-213.314, -157.139], + [-221.425, -155.267], + [-245.259, -114.089], + [-242.805, -106.185], + [-208.905, -72.66], + [-186.86, -12.099], + [-186.86, 12.109], + [-208.905, 72.671], + [-242.805, 106.195], + [-245.259, 114.099], + [-221.425, 155.236], + [-213.314, 157.15], + [-167.477, 144.547], + [-103.838, 155.777], + [-82.999, 167.839], + [-41.529, 217.295], + [-29.508, 263.257], + [-23.81, 269.329], + [23.691, 269.329], + [29.39, 263.257], + [41.411, 217.295], + [82.922, 167.839], + [103.719, 155.777], + [167.317, 144.547], + [213.196, 157.15], + [221.307, 155.277], + [245.141, 114.099], + [242.687, 106.195], + [208.787, 72.671], + [186.742, 12.109], + [186.742, -12.098], + [208.787, -72.66], + [242.687, -106.185], + [245.141, -114.089], + [221.307, -155.225], + [213.196, -157.139], + [167.359, -144.536], + [103.719, -155.766], + [82.88, -167.828], + [41.411, -217.285], + [29.39, -263.247], + [23.691, -269.32] + ], + "c": true + }, + "ix": 2 + }, + "nm": "Path 3", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ind": 3, + "ty": "sh", + "ix": 4, + "ks": { + "a": 0, + "k": { + "i": [ + [-9.816, 0], + [-9.697, -0.846], + [-7.071, -26.828], + [0, 0], + [-5.532, -2.745], + [-8.902, -5.948], + [-2.745, 0.79], + [0, 0], + [-17.802, -25.331], + [-8.236, -17.72], + [19.758, -19.508], + [0, 0], + [-0.416, -6.114], + [0.666, -10.69], + [-2.079, -1.997], + [0, 0], + [13.102, -28.076], + [11.232, -15.979], + [26.787, 7.363], + [0, 0], + [5.117, -3.411], + [9.602, -4.741], + [0.707, -2.745], + [0, 0], + [30.904, -2.663], + [19.401, 1.705], + [7.03, 26.87], + [0, 0], + [5.532, 2.745], + [8.891, 5.969], + [2.746, -0.79], + [0, 0], + [17.802, 25.332], + [8.277, 17.703], + [-19.716, 19.508], + [0, 0], + [0.416, 6.114], + [-0.666, 10.693], + [2.08, 1.997], + [0, 0], + [-13.102, 28.076], + [-11.242, 15.972], + [-26.787, -7.363], + [0, 0], + [-5.116, 3.411], + [-9.608, 4.742], + [-0.707, 2.745], + [0, 0], + [-30.905, 2.704] + ], + "o": [ + [9.733, 0.014], + [30.904, 2.662], + [0, 0], + [0.749, 2.745], + [9.609, 4.742], + [5.116, 3.411], + [0, 0], + [26.787, -7.321], + [11.231, 16.014], + [13.102, 28.076], + [0, 0], + [-2.038, 1.997], + [0.666, 10.69], + [-0.416, 6.114], + [0, 0], + [19.758, 19.508], + [-8.252, 17.703], + [-17.802, 25.373], + [0, 0], + [-2.787, -0.79], + [-8.902, 5.952], + [-5.532, 2.745], + [0, 0], + [-6.987, 26.87], + [-19.402, 1.705], + [-30.905, -2.663], + [0, 0], + [-0.748, -2.745], + [-9.611, -4.723], + [-5.116, -3.411], + [0, 0], + [-26.786, 7.321], + [-11.208, -16.008], + [-13.102, -28.076], + [0, 0], + [2.08, -1.997], + [-0.666, -10.693], + [0.416, -6.114], + [0, 0], + [-19.716, -19.508], + [8.241, -17.709], + [17.802, -25.373], + [0, 0], + [2.787, 0.79], + [8.901, -5.948], + [5.532, -2.745], + [0, 0], + [6.988, -26.87], + [9.608, -0.832] + ], + "v": [ + [-0.059, -332.751], + [29.099, -331.462], + [89.785, -279.095], + [101.764, -233.049], + [110.582, -223.733], + [138.368, -207.676], + [150.804, -204.723], + [196.683, -217.327], + [272.385, -191.123], + [301.668, -140.459], + [286.527, -61.805], + [252.669, -28.28], + [249.009, -16.051], + [249.009, 16.061], + [252.669, 28.289], + [286.527, 61.815], + [301.668, 140.47], + [272.385, 191.09], + [196.683, 217.295], + [150.846, 204.734], + [138.367, 207.687], + [110.582, 223.743], + [101.806, 233.059], + [89.743, 279.063], + [29.099, 331.473], + [-29.217, 331.473], + [-89.862, 279.063], + [-101.883, 233.059], + [-110.701, 223.743], + [-138.486, 207.687], + [-150.923, 204.734], + [-196.802, 217.336], + [-272.504, 191.132], + [-301.786, 140.47], + [-286.687, 61.815], + [-252.788, 28.289], + [-249.127, 16.061], + [-249.127, -16.051], + [-252.788, -28.28], + [-286.687, -61.805], + [-301.786, -140.459], + [-272.504, -191.08], + [-196.801, -217.285], + [-150.964, -204.723], + [-138.486, -207.676], + [-110.701, -223.733], + [-101.924, -233.049], + [-89.862, -279.053], + [-29.217, -331.504] + ], + "c": true + }, + "ix": 2 + }, + "nm": "Path 4", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ty": "mm", + "mm": 1, + "nm": "Merge Paths 1", + "mn": "ADBE Vector Filter - Merge", + "hd": false + }, + { + "ty": "fl", + "c": { + "a": 0, + "k": [0.898460657456, 0.889815326765, 0.896223060758, 1], + "ix": 4 + }, + "o": { "a": 0, "k": 100, "ix": 5 }, + "r": 1, + "bm": 0, + "nm": "Fill 1", + "mn": "ADBE Vector Graphic - Fill", + "hd": false + }, + { + "ty": "tr", + "p": { "a": 0, "k": [308.077, 333.249], "ix": 2 }, + "a": { "a": 0, "k": [0, 0], "ix": 1 }, + "s": { "a": 0, "k": [100, 100], "ix": 3 }, + "r": { "a": 0, "k": 0, "ix": 6 }, + "o": { "a": 0, "k": 100, "ix": 7 }, + "sk": { "a": 0, "k": 0, "ix": 4 }, + "sa": { "a": 0, "k": 0, "ix": 5 }, + "nm": "Transform" + } + ], + "nm": "Group 1", + "np": 8, + "cix": 2, + "bm": 0, + "ix": 1, + "mn": "ADBE Vector Group", + "hd": false + } + ], + "ip": 0, + "op": 120, + "st": 0, + "bm": 0 + } + ], + "markers": [] +} diff --git a/src/renderer/declaration.d.ts b/src/renderer/declaration.d.ts index cceed299..393717ba 100644 --- a/src/renderer/declaration.d.ts +++ b/src/renderer/declaration.d.ts @@ -22,7 +22,8 @@ declare global { repackId: number, objectID: string, title: string, - shop: GameShop + shop: GameShop, + downloadPath: string ) => Promise; cancelGameDownload: (gameId: number) => Promise; pauseGameDownload: (gameId: number) => Promise; diff --git a/src/renderer/hooks/use-download.ts b/src/renderer/hooks/use-download.ts index 522dd2c2..27f90e8d 100644 --- a/src/renderer/hooks/use-download.ts +++ b/src/renderer/hooks/use-download.ts @@ -28,10 +28,11 @@ export function useDownload() { repackId: number, objectID: string, title: string, - shop: GameShop + shop: GameShop, + downloadPath: string ) => window.electron - .startGameDownload(repackId, objectID, title, shop) + .startGameDownload(repackId, objectID, title, shop, downloadPath) .then((game) => { dispatch(clearDownload()); updateLibrary(); diff --git a/src/renderer/pages/game-details/game-details.tsx b/src/renderer/pages/game-details/game-details.tsx index 12d9d940..88e91ba2 100644 --- a/src/renderer/pages/game-details/game-details.tsx +++ b/src/renderer/pages/game-details/game-details.tsx @@ -138,12 +138,16 @@ export function GameDetails() { }; }, [game?.id, isGamePlaying, getGame]); - const handleStartDownload = async (repackId: number) => { + const handleStartDownload = async ( + repackId: number, + downloadPath: string + ) => { return startDownload( repackId, gameDetails.objectID, gameDetails.name, - shop as GameShop + shop as GameShop, + downloadPath ).then(() => { getGame(); setShowRepacksModal(false); diff --git a/src/renderer/pages/game-details/repacks-modal.tsx b/src/renderer/pages/game-details/repacks-modal.tsx index b3917b23..bb47060e 100644 --- a/src/renderer/pages/game-details/repacks-modal.tsx +++ b/src/renderer/pages/game-details/repacks-modal.tsx @@ -10,11 +10,12 @@ import type { DiskSpace } from "check-disk-space"; import { format } from "date-fns"; import { SPACING_UNIT } from "@renderer/theme.css"; import { formatBytes } from "@renderer/utils"; +import { SelectFolderModal } from "./select-folder-modal"; export interface RepacksModalProps { visible: boolean; gameDetails: ShopDetails; - startDownload: (repackId: number) => Promise; + startDownload: (repackId: number, downloadPath: string) => Promise; onClose: () => void; } @@ -24,9 +25,10 @@ export function RepacksModal({ startDownload, onClose, }: RepacksModalProps) { - const [downloadStarting, setDownloadStarting] = useState(false); + const [openSelectFolderModal, setOpenSelectFolderModal] = useState(false); const [diskFreeSpace, setDiskFreeSpace] = useState(null); const [filteredRepacks, setFilteredRepacks] = useState([]); + const [repack, setRepack] = useState(null); const { t } = useTranslation("game_details"); @@ -45,10 +47,8 @@ export function RepacksModal({ }, [visible]); const handleRepackClick = (repack: GameRepack) => { - setDownloadStarting(true); - startDownload(repack.id).finally(() => { - setDownloadStarting(false); - }); + setRepack(repack); + setOpenSelectFolderModal(true); }; const handleFilter: React.ChangeEventHandler = (event) => { @@ -70,6 +70,13 @@ export function RepacksModal({ })} onClose={onClose} > + setOpenSelectFolderModal(false)} + gameDetails={gameDetails} + startDownload={startDownload} + repack={repack} + />
@@ -80,7 +87,6 @@ export function RepacksModal({ key={repack.id} theme="dark" onClick={() => handleRepackClick(repack)} - disabled={downloadStarting} className={styles.repackButton} >

{repack.title}

diff --git a/src/renderer/pages/game-details/select-folder-modal.css.tsx b/src/renderer/pages/game-details/select-folder-modal.css.tsx new file mode 100644 index 00000000..7d32bccc --- /dev/null +++ b/src/renderer/pages/game-details/select-folder-modal.css.tsx @@ -0,0 +1,19 @@ +import { style } from "@vanilla-extract/css"; +import { SPACING_UNIT, vars } from "@renderer/theme.css"; + +export const container = style({ + display: "flex", + flexDirection: "column", + gap: `${SPACING_UNIT * 2}px`, + width: "100%", +}); + +export const downloadsPathField = style({ + display: "flex", + gap: `${SPACING_UNIT * 2}px`, +}); + +export const hintText = style({ + fontSize: 12, + color: vars.color.bodyText, +}); diff --git a/src/renderer/pages/game-details/select-folder-modal.tsx b/src/renderer/pages/game-details/select-folder-modal.tsx new file mode 100644 index 00000000..4ba06ece --- /dev/null +++ b/src/renderer/pages/game-details/select-folder-modal.tsx @@ -0,0 +1,103 @@ +import { Button, Modal, TextField } from "@renderer/components"; +import { GameRepack, ShopDetails } from "@types"; +import { useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; + +import * as styles from "./select-folder-modal.css"; +import { Link } from "react-router-dom"; + +export interface SelectFolderModalProps { + visible: boolean; + gameDetails: ShopDetails; + onClose: () => void; + startDownload: (repackId: number, downloadPath: string) => Promise; + repack: GameRepack; +} + +export function SelectFolderModal({ + visible, + gameDetails, + onClose, + startDownload, + repack, +}: SelectFolderModalProps) { + const { t } = useTranslation("game_details"); + + const [selectedPath, setSelectedPath] = useState({ + downloadsPath: "", + }); + const [downloadStarting, setDownloadStarting] = useState(false); + + useEffect(() => { + Promise.all([ + window.electron.getDefaultDownloadsPath(), + window.electron.getUserPreferences(), + ]).then(([path, userPreferences]) => { + setSelectedPath({ + downloadsPath: userPreferences?.downloadsPath || path, + }); + }); + }, []); + + const handleChooseDownloadsPath = async () => { + const { filePaths } = await window.electron.showOpenDialog({ + defaultPath: selectedPath.downloadsPath, + properties: ["openDirectory"], + }); + + if (filePaths && filePaths.length > 0) { + const path = filePaths[0]; + setSelectedPath({ downloadsPath: path }); + } + }; + + const handleStartClick = () => { + setDownloadStarting(true); + startDownload(repack.id, selectedPath.downloadsPath).finally(() => { + setDownloadStarting(false); + }); + }; + + return ( + +
+
+ + + +
+

+ {t("select_folder_hint")}{" "} + + {t("hydra_settings")} + +

+ +
+
+ ); +} From 98d883b7f114e76229528dbd40119c3b67cc5f9e Mon Sep 17 00:00:00 2001 From: shadowtosser Date: Sat, 20 Apr 2024 21:11:01 -0300 Subject: [PATCH 003/140] fix: select Folder Modal doesn't close --- src/renderer/pages/game-details/game-details.tsx | 4 ++++ src/renderer/pages/game-details/repacks-modal.tsx | 11 +++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/renderer/pages/game-details/game-details.tsx b/src/renderer/pages/game-details/game-details.tsx index 9c9178bf..aae3f267 100644 --- a/src/renderer/pages/game-details/game-details.tsx +++ b/src/renderer/pages/game-details/game-details.tsx @@ -51,6 +51,7 @@ export function GameDetails() { const { t, i18n } = useTranslation("game_details"); const [showRepacksModal, setShowRepacksModal] = useState(false); + const [showSelectFolderModal, setShowSelectFolderModal] = useState(false); const randomGameObjectID = useRef(null); @@ -153,6 +154,7 @@ export function GameDetails() { ).then(() => { getGame(); setShowRepacksModal(false); + setShowSelectFolderModal(false); }); }; @@ -177,6 +179,8 @@ export function GameDetails() { visible={showRepacksModal} gameDetails={gameDetails} startDownload={handleStartDownload} + showSelectFolderModal={showSelectFolderModal} + setShowSelectFolderModal={setShowSelectFolderModal} onClose={() => setShowRepacksModal(false)} /> )} diff --git a/src/renderer/pages/game-details/repacks-modal.tsx b/src/renderer/pages/game-details/repacks-modal.tsx index 3282ee3b..7908c486 100644 --- a/src/renderer/pages/game-details/repacks-modal.tsx +++ b/src/renderer/pages/game-details/repacks-modal.tsx @@ -16,6 +16,8 @@ import { SelectFolderModal } from "./select-folder-modal"; export interface RepacksModalProps { visible: boolean; gameDetails: ShopDetails; + showSelectFolderModal: boolean; + setShowSelectFolderModal: (value: boolean) => void; startDownload: (repackId: number, downloadPath: string) => Promise; onClose: () => void; } @@ -23,10 +25,11 @@ export interface RepacksModalProps { export function RepacksModal({ visible, gameDetails, + showSelectFolderModal, + setShowSelectFolderModal, startDownload, onClose, }: RepacksModalProps) { - const [openSelectFolderModal, setOpenSelectFolderModal] = useState(false); const [diskFreeSpace, setDiskFreeSpace] = useState(null); const [filteredRepacks, setFilteredRepacks] = useState([]); const [repack, setRepack] = useState(null); @@ -53,7 +56,7 @@ export function RepacksModal({ const handleRepackClick = (repack: GameRepack) => { setRepack(repack); - setOpenSelectFolderModal(true); + setShowSelectFolderModal(true); }; const handleFilter: React.ChangeEventHandler = (event) => { @@ -76,8 +79,8 @@ export function RepacksModal({ onClose={onClose} > setOpenSelectFolderModal(false)} + visible={showSelectFolderModal} + onClose={() => setShowSelectFolderModal(false)} gameDetails={gameDetails} startDownload={startDownload} repack={repack} From 12fb53908b1b70d51f237969c3fbd03fcfc31d51 Mon Sep 17 00:00:00 2001 From: Hydra Date: Sat, 20 Apr 2024 21:11:01 -0300 Subject: [PATCH 004/140] fix: select Folder Modal doesn't close --- src/renderer/pages/game-details/game-details.tsx | 4 ++++ src/renderer/pages/game-details/repacks-modal.tsx | 11 +++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/renderer/pages/game-details/game-details.tsx b/src/renderer/pages/game-details/game-details.tsx index 9c9178bf..aae3f267 100644 --- a/src/renderer/pages/game-details/game-details.tsx +++ b/src/renderer/pages/game-details/game-details.tsx @@ -51,6 +51,7 @@ export function GameDetails() { const { t, i18n } = useTranslation("game_details"); const [showRepacksModal, setShowRepacksModal] = useState(false); + const [showSelectFolderModal, setShowSelectFolderModal] = useState(false); const randomGameObjectID = useRef(null); @@ -153,6 +154,7 @@ export function GameDetails() { ).then(() => { getGame(); setShowRepacksModal(false); + setShowSelectFolderModal(false); }); }; @@ -177,6 +179,8 @@ export function GameDetails() { visible={showRepacksModal} gameDetails={gameDetails} startDownload={handleStartDownload} + showSelectFolderModal={showSelectFolderModal} + setShowSelectFolderModal={setShowSelectFolderModal} onClose={() => setShowRepacksModal(false)} /> )} diff --git a/src/renderer/pages/game-details/repacks-modal.tsx b/src/renderer/pages/game-details/repacks-modal.tsx index 3282ee3b..7908c486 100644 --- a/src/renderer/pages/game-details/repacks-modal.tsx +++ b/src/renderer/pages/game-details/repacks-modal.tsx @@ -16,6 +16,8 @@ import { SelectFolderModal } from "./select-folder-modal"; export interface RepacksModalProps { visible: boolean; gameDetails: ShopDetails; + showSelectFolderModal: boolean; + setShowSelectFolderModal: (value: boolean) => void; startDownload: (repackId: number, downloadPath: string) => Promise; onClose: () => void; } @@ -23,10 +25,11 @@ export interface RepacksModalProps { export function RepacksModal({ visible, gameDetails, + showSelectFolderModal, + setShowSelectFolderModal, startDownload, onClose, }: RepacksModalProps) { - const [openSelectFolderModal, setOpenSelectFolderModal] = useState(false); const [diskFreeSpace, setDiskFreeSpace] = useState(null); const [filteredRepacks, setFilteredRepacks] = useState([]); const [repack, setRepack] = useState(null); @@ -53,7 +56,7 @@ export function RepacksModal({ const handleRepackClick = (repack: GameRepack) => { setRepack(repack); - setOpenSelectFolderModal(true); + setShowSelectFolderModal(true); }; const handleFilter: React.ChangeEventHandler = (event) => { @@ -76,8 +79,8 @@ export function RepacksModal({ onClose={onClose} > setOpenSelectFolderModal(false)} + visible={showSelectFolderModal} + onClose={() => setShowSelectFolderModal(false)} gameDetails={gameDetails} startDownload={startDownload} repack={repack} From 41f7e5016d3f7ae5aabcee452dc9ae0906d39674 Mon Sep 17 00:00:00 2001 From: shadowtosser Date: Sat, 20 Apr 2024 21:32:10 -0300 Subject: [PATCH 005/140] fix: game dont install in another path after the first installation --- src/main/events/torrenting/start-game-download.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/events/torrenting/start-game-download.ts b/src/main/events/torrenting/start-game-download.ts index f661a956..d6c243b5 100644 --- a/src/main/events/torrenting/start-game-download.ts +++ b/src/main/events/torrenting/start-game-download.ts @@ -37,7 +37,7 @@ const startGameDownload = async ( writePipe.write({ action: "pause" }); - const downloadsPath = game?.downloadPath ?? downloadPath; + const downloadsPath = downloadPath; await gameRepository.update( { From e860b8aeaa78c727e424b948cc4e5ab3c001946a Mon Sep 17 00:00:00 2001 From: Hydra Date: Sat, 20 Apr 2024 21:32:10 -0300 Subject: [PATCH 006/140] fix: game dont install in another path after the first installation --- src/main/events/torrenting/start-game-download.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/events/torrenting/start-game-download.ts b/src/main/events/torrenting/start-game-download.ts index f661a956..d6c243b5 100644 --- a/src/main/events/torrenting/start-game-download.ts +++ b/src/main/events/torrenting/start-game-download.ts @@ -37,7 +37,7 @@ const startGameDownload = async ( writePipe.write({ action: "pause" }); - const downloadsPath = game?.downloadPath ?? downloadPath; + const downloadsPath = downloadPath; await gameRepository.update( { From 1c0810b976e66d0c48c113c5d88fa9288e2c6711 Mon Sep 17 00:00:00 2001 From: shadowtosser Date: Sat, 20 Apr 2024 23:02:30 -0300 Subject: [PATCH 007/140] refactor: changed selectedPath from an object to a string --- .../pages/game-details/select-folder-modal.tsx | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/renderer/pages/game-details/select-folder-modal.tsx b/src/renderer/pages/game-details/select-folder-modal.tsx index 4ba06ece..111c22dc 100644 --- a/src/renderer/pages/game-details/select-folder-modal.tsx +++ b/src/renderer/pages/game-details/select-folder-modal.tsx @@ -23,9 +23,7 @@ export function SelectFolderModal({ }: SelectFolderModalProps) { const { t } = useTranslation("game_details"); - const [selectedPath, setSelectedPath] = useState({ - downloadsPath: "", - }); + const [selectedPath, setSelectedPath] = useState(null); const [downloadStarting, setDownloadStarting] = useState(false); useEffect(() => { @@ -33,9 +31,7 @@ export function SelectFolderModal({ window.electron.getDefaultDownloadsPath(), window.electron.getUserPreferences(), ]).then(([path, userPreferences]) => { - setSelectedPath({ - downloadsPath: userPreferences?.downloadsPath || path, - }); + setSelectedPath(userPreferences?.downloadsPath || path); }); }, []); @@ -47,7 +43,7 @@ export function SelectFolderModal({ if (filePaths && filePaths.length > 0) { const path = filePaths[0]; - setSelectedPath({ downloadsPath: path }); + setSelectedPath(path); } }; From fca84f7c90dc893b7683713b4b03e37aa981099c Mon Sep 17 00:00:00 2001 From: Hydra Date: Sat, 20 Apr 2024 23:02:30 -0300 Subject: [PATCH 008/140] refactor: changed selectedPath from an object to a string --- .../pages/game-details/select-folder-modal.tsx | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/renderer/pages/game-details/select-folder-modal.tsx b/src/renderer/pages/game-details/select-folder-modal.tsx index 4ba06ece..111c22dc 100644 --- a/src/renderer/pages/game-details/select-folder-modal.tsx +++ b/src/renderer/pages/game-details/select-folder-modal.tsx @@ -23,9 +23,7 @@ export function SelectFolderModal({ }: SelectFolderModalProps) { const { t } = useTranslation("game_details"); - const [selectedPath, setSelectedPath] = useState({ - downloadsPath: "", - }); + const [selectedPath, setSelectedPath] = useState(null); const [downloadStarting, setDownloadStarting] = useState(false); useEffect(() => { @@ -33,9 +31,7 @@ export function SelectFolderModal({ window.electron.getDefaultDownloadsPath(), window.electron.getUserPreferences(), ]).then(([path, userPreferences]) => { - setSelectedPath({ - downloadsPath: userPreferences?.downloadsPath || path, - }); + setSelectedPath(userPreferences?.downloadsPath || path); }); }, []); @@ -47,7 +43,7 @@ export function SelectFolderModal({ if (filePaths && filePaths.length > 0) { const path = filePaths[0]; - setSelectedPath({ downloadsPath: path }); + setSelectedPath(path); } }; From 64842dc77d952705c1e560e8b88b43867bd5d3bb Mon Sep 17 00:00:00 2001 From: shadowtosser Date: Sat, 20 Apr 2024 23:03:27 -0300 Subject: [PATCH 009/140] refactor: remove downloadPath constant to get directly from props --- src/main/events/torrenting/start-game-download.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/main/events/torrenting/start-game-download.ts b/src/main/events/torrenting/start-game-download.ts index d6c243b5..d5143221 100644 --- a/src/main/events/torrenting/start-game-download.ts +++ b/src/main/events/torrenting/start-game-download.ts @@ -37,8 +37,6 @@ const startGameDownload = async ( writePipe.write({ action: "pause" }); - const downloadsPath = downloadPath; - await gameRepository.update( { status: In([ @@ -57,7 +55,7 @@ const startGameDownload = async ( }, { status: GameStatus.DownloadingMetadata, - downloadPath: downloadsPath, + downloadPath: downloadPath, repack: { id: repackId }, } ); @@ -66,7 +64,7 @@ const startGameDownload = async ( action: "start", game_id: game.id, magnet: repack.magnet, - save_path: downloadsPath, + save_path: downloadPath, }); game.status = GameStatus.DownloadingMetadata; @@ -75,7 +73,7 @@ const startGameDownload = async ( action: "start", game_id: game.id, magnet: repack.magnet, - save_path: downloadsPath, + save_path: downloadPath, }); return game; @@ -88,7 +86,7 @@ const startGameDownload = async ( objectID, shop: gameShop, status: GameStatus.DownloadingMetadata, - downloadPath: downloadsPath, + downloadPath: downloadPath, repack: { id: repackId }, }); @@ -96,7 +94,7 @@ const startGameDownload = async ( action: "start", game_id: createdGame.id, magnet: repack.magnet, - save_path: downloadsPath, + save_path: downloadPath, }); const { repack: _, ...rest } = createdGame; From 93ff4b8f7a8908d901445cfdef4f1cf54b3c6951 Mon Sep 17 00:00:00 2001 From: Hydra Date: Sat, 20 Apr 2024 23:03:27 -0300 Subject: [PATCH 010/140] refactor: remove downloadPath constant to get directly from props --- src/main/events/torrenting/start-game-download.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/main/events/torrenting/start-game-download.ts b/src/main/events/torrenting/start-game-download.ts index d6c243b5..d5143221 100644 --- a/src/main/events/torrenting/start-game-download.ts +++ b/src/main/events/torrenting/start-game-download.ts @@ -37,8 +37,6 @@ const startGameDownload = async ( writePipe.write({ action: "pause" }); - const downloadsPath = downloadPath; - await gameRepository.update( { status: In([ @@ -57,7 +55,7 @@ const startGameDownload = async ( }, { status: GameStatus.DownloadingMetadata, - downloadPath: downloadsPath, + downloadPath: downloadPath, repack: { id: repackId }, } ); @@ -66,7 +64,7 @@ const startGameDownload = async ( action: "start", game_id: game.id, magnet: repack.magnet, - save_path: downloadsPath, + save_path: downloadPath, }); game.status = GameStatus.DownloadingMetadata; @@ -75,7 +73,7 @@ const startGameDownload = async ( action: "start", game_id: game.id, magnet: repack.magnet, - save_path: downloadsPath, + save_path: downloadPath, }); return game; @@ -88,7 +86,7 @@ const startGameDownload = async ( objectID, shop: gameShop, status: GameStatus.DownloadingMetadata, - downloadPath: downloadsPath, + downloadPath: downloadPath, repack: { id: repackId }, }); @@ -96,7 +94,7 @@ const startGameDownload = async ( action: "start", game_id: createdGame.id, magnet: repack.magnet, - save_path: downloadsPath, + save_path: downloadPath, }); const { repack: _, ...rest } = createdGame; From 23f1eb82dbb99815c53966e327495503b7472789 Mon Sep 17 00:00:00 2001 From: shadowtosser Date: Sat, 20 Apr 2024 23:09:05 -0300 Subject: [PATCH 011/140] fix: cannot read properties of undefined in selectFolderModal --- src/renderer/pages/game-details/select-folder-modal.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/renderer/pages/game-details/select-folder-modal.tsx b/src/renderer/pages/game-details/select-folder-modal.tsx index 111c22dc..4edfa6b1 100644 --- a/src/renderer/pages/game-details/select-folder-modal.tsx +++ b/src/renderer/pages/game-details/select-folder-modal.tsx @@ -23,7 +23,7 @@ export function SelectFolderModal({ }: SelectFolderModalProps) { const { t } = useTranslation("game_details"); - const [selectedPath, setSelectedPath] = useState(null); + const [selectedPath, setSelectedPath] = useState(""); const [downloadStarting, setDownloadStarting] = useState(false); useEffect(() => { @@ -37,7 +37,7 @@ export function SelectFolderModal({ const handleChooseDownloadsPath = async () => { const { filePaths } = await window.electron.showOpenDialog({ - defaultPath: selectedPath.downloadsPath, + defaultPath: selectedPath, properties: ["openDirectory"], }); @@ -49,7 +49,7 @@ export function SelectFolderModal({ const handleStartClick = () => { setDownloadStarting(true); - startDownload(repack.id, selectedPath.downloadsPath).finally(() => { + startDownload(repack.id, selectedPath).finally(() => { setDownloadStarting(false); }); }; @@ -65,7 +65,7 @@ export function SelectFolderModal({
From 5db7b97090f13389d5661d20f6d3e189b950d077 Mon Sep 17 00:00:00 2001 From: Hydra Date: Sat, 20 Apr 2024 23:09:05 -0300 Subject: [PATCH 012/140] fix: cannot read properties of undefined in selectFolderModal --- src/renderer/pages/game-details/select-folder-modal.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/renderer/pages/game-details/select-folder-modal.tsx b/src/renderer/pages/game-details/select-folder-modal.tsx index 111c22dc..4edfa6b1 100644 --- a/src/renderer/pages/game-details/select-folder-modal.tsx +++ b/src/renderer/pages/game-details/select-folder-modal.tsx @@ -23,7 +23,7 @@ export function SelectFolderModal({ }: SelectFolderModalProps) { const { t } = useTranslation("game_details"); - const [selectedPath, setSelectedPath] = useState(null); + const [selectedPath, setSelectedPath] = useState(""); const [downloadStarting, setDownloadStarting] = useState(false); useEffect(() => { @@ -37,7 +37,7 @@ export function SelectFolderModal({ const handleChooseDownloadsPath = async () => { const { filePaths } = await window.electron.showOpenDialog({ - defaultPath: selectedPath.downloadsPath, + defaultPath: selectedPath, properties: ["openDirectory"], }); @@ -49,7 +49,7 @@ export function SelectFolderModal({ const handleStartClick = () => { setDownloadStarting(true); - startDownload(repack.id, selectedPath.downloadsPath).finally(() => { + startDownload(repack.id, selectedPath).finally(() => { setDownloadStarting(false); }); }; @@ -65,7 +65,7 @@ export function SelectFolderModal({
From fea8f44c17775d47b7644342a926f37b6225f1dc Mon Sep 17 00:00:00 2001 From: shadowtosser Date: Sun, 21 Apr 2024 00:59:52 -0300 Subject: [PATCH 013/140] feat: change selectFolderModal to a section inside repacksModal --- .../events/hardware/get-disk-free-space.ts | 5 +- src/preload.ts | 2 +- src/renderer/declaration.d.ts | 2 +- .../pages/game-details/game-details.tsx | 4 - .../pages/game-details/repacks-modal.css.ts | 20 ++++ .../pages/game-details/repacks-modal.tsx | 108 +++++++++++++----- .../game-details/select-folder-modal.css.tsx | 19 --- .../game-details/select-folder-modal.tsx | 99 ---------------- 8 files changed, 101 insertions(+), 158 deletions(-) delete mode 100644 src/renderer/pages/game-details/select-folder-modal.css.tsx delete mode 100644 src/renderer/pages/game-details/select-folder-modal.tsx diff --git a/src/main/events/hardware/get-disk-free-space.ts b/src/main/events/hardware/get-disk-free-space.ts index 28dcafa2..427988d6 100644 --- a/src/main/events/hardware/get-disk-free-space.ts +++ b/src/main/events/hardware/get-disk-free-space.ts @@ -1,10 +1,9 @@ import checkDiskSpace from "check-disk-space"; import { registerEvent } from "../register-event"; -import { getDownloadsPath } from "../helpers/get-downloads-path"; -const getDiskFreeSpace = async (_event: Electron.IpcMainInvokeEvent) => - checkDiskSpace(await getDownloadsPath()); +const getDiskFreeSpace = async (_event: Electron.IpcMainInvokeEvent, path: string) => + checkDiskSpace(path); registerEvent(getDiskFreeSpace, { name: "getDiskFreeSpace", diff --git a/src/preload.ts b/src/preload.ts index ec36b67a..b01ab524 100644 --- a/src/preload.ts +++ b/src/preload.ts @@ -99,7 +99,7 @@ contextBridge.exposeInMainWorld("electron", { }, /* Hardware */ - getDiskFreeSpace: () => ipcRenderer.invoke("getDiskFreeSpace"), + getDiskFreeSpace: (path: string) => ipcRenderer.invoke("getDiskFreeSpace", path), /* Misc */ getOrCacheImage: (url: string) => ipcRenderer.invoke("getOrCacheImage", url), diff --git a/src/renderer/declaration.d.ts b/src/renderer/declaration.d.ts index f8d1018c..3184940a 100644 --- a/src/renderer/declaration.d.ts +++ b/src/renderer/declaration.d.ts @@ -76,7 +76,7 @@ declare global { ) => Promise; /* Hardware */ - getDiskFreeSpace: () => Promise; + getDiskFreeSpace: (path: string) => Promise; /* Misc */ getOrCacheImage: (url: string) => Promise; diff --git a/src/renderer/pages/game-details/game-details.tsx b/src/renderer/pages/game-details/game-details.tsx index aae3f267..9c9178bf 100644 --- a/src/renderer/pages/game-details/game-details.tsx +++ b/src/renderer/pages/game-details/game-details.tsx @@ -51,7 +51,6 @@ export function GameDetails() { const { t, i18n } = useTranslation("game_details"); const [showRepacksModal, setShowRepacksModal] = useState(false); - const [showSelectFolderModal, setShowSelectFolderModal] = useState(false); const randomGameObjectID = useRef(null); @@ -154,7 +153,6 @@ export function GameDetails() { ).then(() => { getGame(); setShowRepacksModal(false); - setShowSelectFolderModal(false); }); }; @@ -179,8 +177,6 @@ export function GameDetails() { visible={showRepacksModal} gameDetails={gameDetails} startDownload={handleStartDownload} - showSelectFolderModal={showSelectFolderModal} - setShowSelectFolderModal={setShowSelectFolderModal} onClose={() => setShowRepacksModal(false)} /> )} diff --git a/src/renderer/pages/game-details/repacks-modal.css.ts b/src/renderer/pages/game-details/repacks-modal.css.ts index c2568594..4133d1a7 100644 --- a/src/renderer/pages/game-details/repacks-modal.css.ts +++ b/src/renderer/pages/game-details/repacks-modal.css.ts @@ -16,3 +16,23 @@ export const repackButton = style({ color: vars.color.bodyText, padding: `${SPACING_UNIT * 2}px`, }); + +export const container = style({ + width: "100%", + display: "flex", + flexDirection: "column", + gap: `${SPACING_UNIT * 2}px`, + marginBottom: SPACING_UNIT * 2, + paddingBottom: SPACING_UNIT * 2, + borderBottom: `solid 1px ${vars.color.borderColor}`, +}); + +export const downloadsPathField = style({ + display: "flex", + gap: `${SPACING_UNIT * 2}px`, +}); + +export const hintText = style({ + fontSize: 12, + color: vars.color.bodyText, +}); \ No newline at end of file diff --git a/src/renderer/pages/game-details/repacks-modal.tsx b/src/renderer/pages/game-details/repacks-modal.tsx index 7908c486..33db267b 100644 --- a/src/renderer/pages/game-details/repacks-modal.tsx +++ b/src/renderer/pages/game-details/repacks-modal.tsx @@ -6,18 +6,16 @@ import type { GameRepack, ShopDetails } from "@types"; import * as styles from "./repacks-modal.css"; -import type { DiskSpace } from "check-disk-space"; -import { format } from "date-fns"; +import { useAppSelector } from "@renderer/hooks"; import { SPACING_UNIT } from "@renderer/theme.css"; import { formatBytes } from "@renderer/utils"; -import { useAppSelector } from "@renderer/hooks"; -import { SelectFolderModal } from "./select-folder-modal"; +import type { DiskSpace } from "check-disk-space"; +import { format } from "date-fns"; +import { Link } from "react-router-dom"; export interface RepacksModalProps { visible: boolean; gameDetails: ShopDetails; - showSelectFolderModal: boolean; - setShowSelectFolderModal: (value: boolean) => void; startDownload: (repackId: number, downloadPath: string) => Promise; onClose: () => void; } @@ -25,18 +23,13 @@ export interface RepacksModalProps { export function RepacksModal({ visible, gameDetails, - showSelectFolderModal, - setShowSelectFolderModal, startDownload, onClose, }: RepacksModalProps) { const [diskFreeSpace, setDiskFreeSpace] = useState(null); const [filteredRepacks, setFilteredRepacks] = useState([]); - const [repack, setRepack] = useState(null); - - const repackersFriendlyNames = useAppSelector( - (state) => state.repackersFriendlyNames.value - ); + const [selectedPath, setSelectedPath] = useState(""); + const [downloadStarting, setDownloadStarting] = useState(false); const { t } = useTranslation("game_details"); @@ -44,20 +37,22 @@ export function RepacksModal({ setFilteredRepacks(gameDetails.repacks); }, [gameDetails.repacks]); - const getDiskFreeSpace = () => { - window.electron.getDiskFreeSpace().then((result) => { - setDiskFreeSpace(result); - }); - }; + useEffect(() => { + visible && getDiskFreeSpace(selectedPath); + }, [selectedPath, visible]); useEffect(() => { - getDiskFreeSpace(); - }, [visible]); + Promise.all([ + window.electron.getDefaultDownloadsPath(), + window.electron.getUserPreferences(), + ]).then(([path, userPreferences]) => { + setSelectedPath(userPreferences?.downloadsPath || path); + }); + }, []); - const handleRepackClick = (repack: GameRepack) => { - setRepack(repack); - setShowSelectFolderModal(true); - }; + const repackersFriendlyNames = useAppSelector( + (state) => state.repackersFriendlyNames.value + ); const handleFilter: React.ChangeEventHandler = (event) => { setFilteredRepacks( @@ -69,6 +64,32 @@ export function RepacksModal({ ); }; + const handleChooseDownloadsPath = async () => { + const { filePaths } = await window.electron.showOpenDialog({ + defaultPath: selectedPath, + properties: ["openDirectory"], + }); + + if (filePaths && filePaths.length > 0) { + const path = filePaths[0]; + setSelectedPath(path); + } + }; + + const handleRepackClick = (repack: GameRepack) => { + setDownloadStarting(true); + startDownload(repack.id, selectedPath).finally(() => { + setDownloadStarting(false); + }); + }; + + const getDiskFreeSpace = (path: string) => { + window.electron.getDiskFreeSpace(path).then((result) => { + setDiskFreeSpace(result); + }); + }; + + return ( - setShowSelectFolderModal(false)} - gameDetails={gameDetails} - startDownload={startDownload} - repack={repack} - /> +
+
+ + + +
+

+ {t("select_folder_hint")}{" "} + + {t("hydra_settings")} + +

+
@@ -96,6 +141,7 @@ export function RepacksModal({ theme="dark" onClick={() => handleRepackClick(repack)} className={styles.repackButton} + disabled={downloadStarting} >

{repack.title}

diff --git a/src/renderer/pages/game-details/select-folder-modal.css.tsx b/src/renderer/pages/game-details/select-folder-modal.css.tsx deleted file mode 100644 index 7d32bccc..00000000 --- a/src/renderer/pages/game-details/select-folder-modal.css.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { style } from "@vanilla-extract/css"; -import { SPACING_UNIT, vars } from "@renderer/theme.css"; - -export const container = style({ - display: "flex", - flexDirection: "column", - gap: `${SPACING_UNIT * 2}px`, - width: "100%", -}); - -export const downloadsPathField = style({ - display: "flex", - gap: `${SPACING_UNIT * 2}px`, -}); - -export const hintText = style({ - fontSize: 12, - color: vars.color.bodyText, -}); diff --git a/src/renderer/pages/game-details/select-folder-modal.tsx b/src/renderer/pages/game-details/select-folder-modal.tsx deleted file mode 100644 index 4edfa6b1..00000000 --- a/src/renderer/pages/game-details/select-folder-modal.tsx +++ /dev/null @@ -1,99 +0,0 @@ -import { Button, Modal, TextField } from "@renderer/components"; -import { GameRepack, ShopDetails } from "@types"; -import { useEffect, useState } from "react"; -import { useTranslation } from "react-i18next"; - -import * as styles from "./select-folder-modal.css"; -import { Link } from "react-router-dom"; - -export interface SelectFolderModalProps { - visible: boolean; - gameDetails: ShopDetails; - onClose: () => void; - startDownload: (repackId: number, downloadPath: string) => Promise; - repack: GameRepack; -} - -export function SelectFolderModal({ - visible, - gameDetails, - onClose, - startDownload, - repack, -}: SelectFolderModalProps) { - const { t } = useTranslation("game_details"); - - const [selectedPath, setSelectedPath] = useState(""); - const [downloadStarting, setDownloadStarting] = useState(false); - - useEffect(() => { - Promise.all([ - window.electron.getDefaultDownloadsPath(), - window.electron.getUserPreferences(), - ]).then(([path, userPreferences]) => { - setSelectedPath(userPreferences?.downloadsPath || path); - }); - }, []); - - const handleChooseDownloadsPath = async () => { - const { filePaths } = await window.electron.showOpenDialog({ - defaultPath: selectedPath, - properties: ["openDirectory"], - }); - - if (filePaths && filePaths.length > 0) { - const path = filePaths[0]; - setSelectedPath(path); - } - }; - - const handleStartClick = () => { - setDownloadStarting(true); - startDownload(repack.id, selectedPath).finally(() => { - setDownloadStarting(false); - }); - }; - - return ( - -

-
- - - -
-

- {t("select_folder_hint")}{" "} - - {t("hydra_settings")} - -

- -
-
- ); -} From 433e00bb500fb7110eebe8b41f56cfac468063ed Mon Sep 17 00:00:00 2001 From: Hydra Date: Sun, 21 Apr 2024 00:59:52 -0300 Subject: [PATCH 014/140] feat: change selectFolderModal to a section inside repacksModal --- .../events/hardware/get-disk-free-space.ts | 5 +- src/preload.ts | 2 +- src/renderer/declaration.d.ts | 2 +- .../pages/game-details/game-details.tsx | 4 - .../pages/game-details/repacks-modal.css.ts | 20 ++++ .../pages/game-details/repacks-modal.tsx | 108 +++++++++++++----- .../game-details/select-folder-modal.css.tsx | 19 --- .../game-details/select-folder-modal.tsx | 99 ---------------- 8 files changed, 101 insertions(+), 158 deletions(-) delete mode 100644 src/renderer/pages/game-details/select-folder-modal.css.tsx delete mode 100644 src/renderer/pages/game-details/select-folder-modal.tsx diff --git a/src/main/events/hardware/get-disk-free-space.ts b/src/main/events/hardware/get-disk-free-space.ts index 28dcafa2..427988d6 100644 --- a/src/main/events/hardware/get-disk-free-space.ts +++ b/src/main/events/hardware/get-disk-free-space.ts @@ -1,10 +1,9 @@ import checkDiskSpace from "check-disk-space"; import { registerEvent } from "../register-event"; -import { getDownloadsPath } from "../helpers/get-downloads-path"; -const getDiskFreeSpace = async (_event: Electron.IpcMainInvokeEvent) => - checkDiskSpace(await getDownloadsPath()); +const getDiskFreeSpace = async (_event: Electron.IpcMainInvokeEvent, path: string) => + checkDiskSpace(path); registerEvent(getDiskFreeSpace, { name: "getDiskFreeSpace", diff --git a/src/preload.ts b/src/preload.ts index ec36b67a..b01ab524 100644 --- a/src/preload.ts +++ b/src/preload.ts @@ -99,7 +99,7 @@ contextBridge.exposeInMainWorld("electron", { }, /* Hardware */ - getDiskFreeSpace: () => ipcRenderer.invoke("getDiskFreeSpace"), + getDiskFreeSpace: (path: string) => ipcRenderer.invoke("getDiskFreeSpace", path), /* Misc */ getOrCacheImage: (url: string) => ipcRenderer.invoke("getOrCacheImage", url), diff --git a/src/renderer/declaration.d.ts b/src/renderer/declaration.d.ts index f8d1018c..3184940a 100644 --- a/src/renderer/declaration.d.ts +++ b/src/renderer/declaration.d.ts @@ -76,7 +76,7 @@ declare global { ) => Promise; /* Hardware */ - getDiskFreeSpace: () => Promise; + getDiskFreeSpace: (path: string) => Promise; /* Misc */ getOrCacheImage: (url: string) => Promise; diff --git a/src/renderer/pages/game-details/game-details.tsx b/src/renderer/pages/game-details/game-details.tsx index aae3f267..9c9178bf 100644 --- a/src/renderer/pages/game-details/game-details.tsx +++ b/src/renderer/pages/game-details/game-details.tsx @@ -51,7 +51,6 @@ export function GameDetails() { const { t, i18n } = useTranslation("game_details"); const [showRepacksModal, setShowRepacksModal] = useState(false); - const [showSelectFolderModal, setShowSelectFolderModal] = useState(false); const randomGameObjectID = useRef(null); @@ -154,7 +153,6 @@ export function GameDetails() { ).then(() => { getGame(); setShowRepacksModal(false); - setShowSelectFolderModal(false); }); }; @@ -179,8 +177,6 @@ export function GameDetails() { visible={showRepacksModal} gameDetails={gameDetails} startDownload={handleStartDownload} - showSelectFolderModal={showSelectFolderModal} - setShowSelectFolderModal={setShowSelectFolderModal} onClose={() => setShowRepacksModal(false)} /> )} diff --git a/src/renderer/pages/game-details/repacks-modal.css.ts b/src/renderer/pages/game-details/repacks-modal.css.ts index c2568594..4133d1a7 100644 --- a/src/renderer/pages/game-details/repacks-modal.css.ts +++ b/src/renderer/pages/game-details/repacks-modal.css.ts @@ -16,3 +16,23 @@ export const repackButton = style({ color: vars.color.bodyText, padding: `${SPACING_UNIT * 2}px`, }); + +export const container = style({ + width: "100%", + display: "flex", + flexDirection: "column", + gap: `${SPACING_UNIT * 2}px`, + marginBottom: SPACING_UNIT * 2, + paddingBottom: SPACING_UNIT * 2, + borderBottom: `solid 1px ${vars.color.borderColor}`, +}); + +export const downloadsPathField = style({ + display: "flex", + gap: `${SPACING_UNIT * 2}px`, +}); + +export const hintText = style({ + fontSize: 12, + color: vars.color.bodyText, +}); \ No newline at end of file diff --git a/src/renderer/pages/game-details/repacks-modal.tsx b/src/renderer/pages/game-details/repacks-modal.tsx index 7908c486..33db267b 100644 --- a/src/renderer/pages/game-details/repacks-modal.tsx +++ b/src/renderer/pages/game-details/repacks-modal.tsx @@ -6,18 +6,16 @@ import type { GameRepack, ShopDetails } from "@types"; import * as styles from "./repacks-modal.css"; -import type { DiskSpace } from "check-disk-space"; -import { format } from "date-fns"; +import { useAppSelector } from "@renderer/hooks"; import { SPACING_UNIT } from "@renderer/theme.css"; import { formatBytes } from "@renderer/utils"; -import { useAppSelector } from "@renderer/hooks"; -import { SelectFolderModal } from "./select-folder-modal"; +import type { DiskSpace } from "check-disk-space"; +import { format } from "date-fns"; +import { Link } from "react-router-dom"; export interface RepacksModalProps { visible: boolean; gameDetails: ShopDetails; - showSelectFolderModal: boolean; - setShowSelectFolderModal: (value: boolean) => void; startDownload: (repackId: number, downloadPath: string) => Promise; onClose: () => void; } @@ -25,18 +23,13 @@ export interface RepacksModalProps { export function RepacksModal({ visible, gameDetails, - showSelectFolderModal, - setShowSelectFolderModal, startDownload, onClose, }: RepacksModalProps) { const [diskFreeSpace, setDiskFreeSpace] = useState(null); const [filteredRepacks, setFilteredRepacks] = useState([]); - const [repack, setRepack] = useState(null); - - const repackersFriendlyNames = useAppSelector( - (state) => state.repackersFriendlyNames.value - ); + const [selectedPath, setSelectedPath] = useState(""); + const [downloadStarting, setDownloadStarting] = useState(false); const { t } = useTranslation("game_details"); @@ -44,20 +37,22 @@ export function RepacksModal({ setFilteredRepacks(gameDetails.repacks); }, [gameDetails.repacks]); - const getDiskFreeSpace = () => { - window.electron.getDiskFreeSpace().then((result) => { - setDiskFreeSpace(result); - }); - }; + useEffect(() => { + visible && getDiskFreeSpace(selectedPath); + }, [selectedPath, visible]); useEffect(() => { - getDiskFreeSpace(); - }, [visible]); + Promise.all([ + window.electron.getDefaultDownloadsPath(), + window.electron.getUserPreferences(), + ]).then(([path, userPreferences]) => { + setSelectedPath(userPreferences?.downloadsPath || path); + }); + }, []); - const handleRepackClick = (repack: GameRepack) => { - setRepack(repack); - setShowSelectFolderModal(true); - }; + const repackersFriendlyNames = useAppSelector( + (state) => state.repackersFriendlyNames.value + ); const handleFilter: React.ChangeEventHandler = (event) => { setFilteredRepacks( @@ -69,6 +64,32 @@ export function RepacksModal({ ); }; + const handleChooseDownloadsPath = async () => { + const { filePaths } = await window.electron.showOpenDialog({ + defaultPath: selectedPath, + properties: ["openDirectory"], + }); + + if (filePaths && filePaths.length > 0) { + const path = filePaths[0]; + setSelectedPath(path); + } + }; + + const handleRepackClick = (repack: GameRepack) => { + setDownloadStarting(true); + startDownload(repack.id, selectedPath).finally(() => { + setDownloadStarting(false); + }); + }; + + const getDiskFreeSpace = (path: string) => { + window.electron.getDiskFreeSpace(path).then((result) => { + setDiskFreeSpace(result); + }); + }; + + return ( - setShowSelectFolderModal(false)} - gameDetails={gameDetails} - startDownload={startDownload} - repack={repack} - /> +
+
+ + + +
+

+ {t("select_folder_hint")}{" "} + + {t("hydra_settings")} + +

+
@@ -96,6 +141,7 @@ export function RepacksModal({ theme="dark" onClick={() => handleRepackClick(repack)} className={styles.repackButton} + disabled={downloadStarting} >

{repack.title}

diff --git a/src/renderer/pages/game-details/select-folder-modal.css.tsx b/src/renderer/pages/game-details/select-folder-modal.css.tsx deleted file mode 100644 index 7d32bccc..00000000 --- a/src/renderer/pages/game-details/select-folder-modal.css.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import { style } from "@vanilla-extract/css"; -import { SPACING_UNIT, vars } from "@renderer/theme.css"; - -export const container = style({ - display: "flex", - flexDirection: "column", - gap: `${SPACING_UNIT * 2}px`, - width: "100%", -}); - -export const downloadsPathField = style({ - display: "flex", - gap: `${SPACING_UNIT * 2}px`, -}); - -export const hintText = style({ - fontSize: 12, - color: vars.color.bodyText, -}); diff --git a/src/renderer/pages/game-details/select-folder-modal.tsx b/src/renderer/pages/game-details/select-folder-modal.tsx deleted file mode 100644 index 4edfa6b1..00000000 --- a/src/renderer/pages/game-details/select-folder-modal.tsx +++ /dev/null @@ -1,99 +0,0 @@ -import { Button, Modal, TextField } from "@renderer/components"; -import { GameRepack, ShopDetails } from "@types"; -import { useEffect, useState } from "react"; -import { useTranslation } from "react-i18next"; - -import * as styles from "./select-folder-modal.css"; -import { Link } from "react-router-dom"; - -export interface SelectFolderModalProps { - visible: boolean; - gameDetails: ShopDetails; - onClose: () => void; - startDownload: (repackId: number, downloadPath: string) => Promise; - repack: GameRepack; -} - -export function SelectFolderModal({ - visible, - gameDetails, - onClose, - startDownload, - repack, -}: SelectFolderModalProps) { - const { t } = useTranslation("game_details"); - - const [selectedPath, setSelectedPath] = useState(""); - const [downloadStarting, setDownloadStarting] = useState(false); - - useEffect(() => { - Promise.all([ - window.electron.getDefaultDownloadsPath(), - window.electron.getUserPreferences(), - ]).then(([path, userPreferences]) => { - setSelectedPath(userPreferences?.downloadsPath || path); - }); - }, []); - - const handleChooseDownloadsPath = async () => { - const { filePaths } = await window.electron.showOpenDialog({ - defaultPath: selectedPath, - properties: ["openDirectory"], - }); - - if (filePaths && filePaths.length > 0) { - const path = filePaths[0]; - setSelectedPath(path); - } - }; - - const handleStartClick = () => { - setDownloadStarting(true); - startDownload(repack.id, selectedPath).finally(() => { - setDownloadStarting(false); - }); - }; - - return ( - -

-
- - - -
-

- {t("select_folder_hint")}{" "} - - {t("hydra_settings")} - -

- -
-
- ); -} From 9627eae1d216bc35722d4f5f6bedbf539d96a71c Mon Sep 17 00:00:00 2001 From: shadowtosser Date: Sun, 21 Apr 2024 01:02:17 -0300 Subject: [PATCH 015/140] prettier: format all files --- src/main/events/hardware/get-disk-free-space.ts | 6 ++++-- src/preload.ts | 3 ++- src/renderer/pages/game-details/repacks-modal.css.ts | 2 +- src/renderer/pages/game-details/repacks-modal.tsx | 3 +-- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/events/hardware/get-disk-free-space.ts b/src/main/events/hardware/get-disk-free-space.ts index 427988d6..0c87ed8b 100644 --- a/src/main/events/hardware/get-disk-free-space.ts +++ b/src/main/events/hardware/get-disk-free-space.ts @@ -2,8 +2,10 @@ import checkDiskSpace from "check-disk-space"; import { registerEvent } from "../register-event"; -const getDiskFreeSpace = async (_event: Electron.IpcMainInvokeEvent, path: string) => - checkDiskSpace(path); +const getDiskFreeSpace = async ( + _event: Electron.IpcMainInvokeEvent, + path: string +) => checkDiskSpace(path); registerEvent(getDiskFreeSpace, { name: "getDiskFreeSpace", diff --git a/src/preload.ts b/src/preload.ts index b01ab524..66fff80f 100644 --- a/src/preload.ts +++ b/src/preload.ts @@ -99,7 +99,8 @@ contextBridge.exposeInMainWorld("electron", { }, /* Hardware */ - getDiskFreeSpace: (path: string) => ipcRenderer.invoke("getDiskFreeSpace", path), + getDiskFreeSpace: (path: string) => + ipcRenderer.invoke("getDiskFreeSpace", path), /* Misc */ getOrCacheImage: (url: string) => ipcRenderer.invoke("getOrCacheImage", url), diff --git a/src/renderer/pages/game-details/repacks-modal.css.ts b/src/renderer/pages/game-details/repacks-modal.css.ts index 4133d1a7..6a1d37f3 100644 --- a/src/renderer/pages/game-details/repacks-modal.css.ts +++ b/src/renderer/pages/game-details/repacks-modal.css.ts @@ -35,4 +35,4 @@ export const downloadsPathField = style({ export const hintText = style({ fontSize: 12, color: vars.color.bodyText, -}); \ No newline at end of file +}); diff --git a/src/renderer/pages/game-details/repacks-modal.tsx b/src/renderer/pages/game-details/repacks-modal.tsx index 33db267b..c5830de7 100644 --- a/src/renderer/pages/game-details/repacks-modal.tsx +++ b/src/renderer/pages/game-details/repacks-modal.tsx @@ -82,14 +82,13 @@ export function RepacksModal({ setDownloadStarting(false); }); }; - + const getDiskFreeSpace = (path: string) => { window.electron.getDiskFreeSpace(path).then((result) => { setDiskFreeSpace(result); }); }; - return ( Date: Sun, 21 Apr 2024 01:02:17 -0300 Subject: [PATCH 016/140] prettier: format all files --- src/main/events/hardware/get-disk-free-space.ts | 6 ++++-- src/preload.ts | 3 ++- src/renderer/pages/game-details/repacks-modal.css.ts | 2 +- src/renderer/pages/game-details/repacks-modal.tsx | 3 +-- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/events/hardware/get-disk-free-space.ts b/src/main/events/hardware/get-disk-free-space.ts index 427988d6..0c87ed8b 100644 --- a/src/main/events/hardware/get-disk-free-space.ts +++ b/src/main/events/hardware/get-disk-free-space.ts @@ -2,8 +2,10 @@ import checkDiskSpace from "check-disk-space"; import { registerEvent } from "../register-event"; -const getDiskFreeSpace = async (_event: Electron.IpcMainInvokeEvent, path: string) => - checkDiskSpace(path); +const getDiskFreeSpace = async ( + _event: Electron.IpcMainInvokeEvent, + path: string +) => checkDiskSpace(path); registerEvent(getDiskFreeSpace, { name: "getDiskFreeSpace", diff --git a/src/preload.ts b/src/preload.ts index b01ab524..66fff80f 100644 --- a/src/preload.ts +++ b/src/preload.ts @@ -99,7 +99,8 @@ contextBridge.exposeInMainWorld("electron", { }, /* Hardware */ - getDiskFreeSpace: (path: string) => ipcRenderer.invoke("getDiskFreeSpace", path), + getDiskFreeSpace: (path: string) => + ipcRenderer.invoke("getDiskFreeSpace", path), /* Misc */ getOrCacheImage: (url: string) => ipcRenderer.invoke("getOrCacheImage", url), diff --git a/src/renderer/pages/game-details/repacks-modal.css.ts b/src/renderer/pages/game-details/repacks-modal.css.ts index 4133d1a7..6a1d37f3 100644 --- a/src/renderer/pages/game-details/repacks-modal.css.ts +++ b/src/renderer/pages/game-details/repacks-modal.css.ts @@ -35,4 +35,4 @@ export const downloadsPathField = style({ export const hintText = style({ fontSize: 12, color: vars.color.bodyText, -}); \ No newline at end of file +}); diff --git a/src/renderer/pages/game-details/repacks-modal.tsx b/src/renderer/pages/game-details/repacks-modal.tsx index 33db267b..c5830de7 100644 --- a/src/renderer/pages/game-details/repacks-modal.tsx +++ b/src/renderer/pages/game-details/repacks-modal.tsx @@ -82,14 +82,13 @@ export function RepacksModal({ setDownloadStarting(false); }); }; - + const getDiskFreeSpace = (path: string) => { window.electron.getDiskFreeSpace(path).then((result) => { setDiskFreeSpace(result); }); }; - return ( Date: Sun, 21 Apr 2024 22:55:00 -0300 Subject: [PATCH 017/140] Revert "feat: change selectFolderModal to a section inside repacksModal" This reverts commit 934fb1145e5ebf9ac47648dbbf5610eed1f2776f. --- src/renderer/declaration.d.ts | 2 +- .../pages/game-details/game-details.tsx | 4 + .../pages/game-details/repacks-modal.css.ts | 20 ---- .../pages/game-details/repacks-modal.tsx | 109 +++++------------- .../game-details/select-folder-modal.css.tsx | 19 +++ .../game-details/select-folder-modal.tsx | 99 ++++++++++++++++ 6 files changed, 155 insertions(+), 98 deletions(-) create mode 100644 src/renderer/pages/game-details/select-folder-modal.css.tsx create mode 100644 src/renderer/pages/game-details/select-folder-modal.tsx diff --git a/src/renderer/declaration.d.ts b/src/renderer/declaration.d.ts index 3184940a..f8d1018c 100644 --- a/src/renderer/declaration.d.ts +++ b/src/renderer/declaration.d.ts @@ -76,7 +76,7 @@ declare global { ) => Promise; /* Hardware */ - getDiskFreeSpace: (path: string) => Promise; + getDiskFreeSpace: () => Promise; /* Misc */ getOrCacheImage: (url: string) => Promise; diff --git a/src/renderer/pages/game-details/game-details.tsx b/src/renderer/pages/game-details/game-details.tsx index 9c9178bf..aae3f267 100644 --- a/src/renderer/pages/game-details/game-details.tsx +++ b/src/renderer/pages/game-details/game-details.tsx @@ -51,6 +51,7 @@ export function GameDetails() { const { t, i18n } = useTranslation("game_details"); const [showRepacksModal, setShowRepacksModal] = useState(false); + const [showSelectFolderModal, setShowSelectFolderModal] = useState(false); const randomGameObjectID = useRef(null); @@ -153,6 +154,7 @@ export function GameDetails() { ).then(() => { getGame(); setShowRepacksModal(false); + setShowSelectFolderModal(false); }); }; @@ -177,6 +179,8 @@ export function GameDetails() { visible={showRepacksModal} gameDetails={gameDetails} startDownload={handleStartDownload} + showSelectFolderModal={showSelectFolderModal} + setShowSelectFolderModal={setShowSelectFolderModal} onClose={() => setShowRepacksModal(false)} /> )} diff --git a/src/renderer/pages/game-details/repacks-modal.css.ts b/src/renderer/pages/game-details/repacks-modal.css.ts index 6a1d37f3..c2568594 100644 --- a/src/renderer/pages/game-details/repacks-modal.css.ts +++ b/src/renderer/pages/game-details/repacks-modal.css.ts @@ -16,23 +16,3 @@ export const repackButton = style({ color: vars.color.bodyText, padding: `${SPACING_UNIT * 2}px`, }); - -export const container = style({ - width: "100%", - display: "flex", - flexDirection: "column", - gap: `${SPACING_UNIT * 2}px`, - marginBottom: SPACING_UNIT * 2, - paddingBottom: SPACING_UNIT * 2, - borderBottom: `solid 1px ${vars.color.borderColor}`, -}); - -export const downloadsPathField = style({ - display: "flex", - gap: `${SPACING_UNIT * 2}px`, -}); - -export const hintText = style({ - fontSize: 12, - color: vars.color.bodyText, -}); diff --git a/src/renderer/pages/game-details/repacks-modal.tsx b/src/renderer/pages/game-details/repacks-modal.tsx index c5830de7..7908c486 100644 --- a/src/renderer/pages/game-details/repacks-modal.tsx +++ b/src/renderer/pages/game-details/repacks-modal.tsx @@ -6,16 +6,18 @@ import type { GameRepack, ShopDetails } from "@types"; import * as styles from "./repacks-modal.css"; -import { useAppSelector } from "@renderer/hooks"; -import { SPACING_UNIT } from "@renderer/theme.css"; -import { formatBytes } from "@renderer/utils"; import type { DiskSpace } from "check-disk-space"; import { format } from "date-fns"; -import { Link } from "react-router-dom"; +import { SPACING_UNIT } from "@renderer/theme.css"; +import { formatBytes } from "@renderer/utils"; +import { useAppSelector } from "@renderer/hooks"; +import { SelectFolderModal } from "./select-folder-modal"; export interface RepacksModalProps { visible: boolean; gameDetails: ShopDetails; + showSelectFolderModal: boolean; + setShowSelectFolderModal: (value: boolean) => void; startDownload: (repackId: number, downloadPath: string) => Promise; onClose: () => void; } @@ -23,13 +25,18 @@ export interface RepacksModalProps { export function RepacksModal({ visible, gameDetails, + showSelectFolderModal, + setShowSelectFolderModal, startDownload, onClose, }: RepacksModalProps) { const [diskFreeSpace, setDiskFreeSpace] = useState(null); const [filteredRepacks, setFilteredRepacks] = useState([]); - const [selectedPath, setSelectedPath] = useState(""); - const [downloadStarting, setDownloadStarting] = useState(false); + const [repack, setRepack] = useState(null); + + const repackersFriendlyNames = useAppSelector( + (state) => state.repackersFriendlyNames.value + ); const { t } = useTranslation("game_details"); @@ -37,22 +44,20 @@ export function RepacksModal({ setFilteredRepacks(gameDetails.repacks); }, [gameDetails.repacks]); - useEffect(() => { - visible && getDiskFreeSpace(selectedPath); - }, [selectedPath, visible]); - - useEffect(() => { - Promise.all([ - window.electron.getDefaultDownloadsPath(), - window.electron.getUserPreferences(), - ]).then(([path, userPreferences]) => { - setSelectedPath(userPreferences?.downloadsPath || path); + const getDiskFreeSpace = () => { + window.electron.getDiskFreeSpace().then((result) => { + setDiskFreeSpace(result); }); - }, []); + }; - const repackersFriendlyNames = useAppSelector( - (state) => state.repackersFriendlyNames.value - ); + useEffect(() => { + getDiskFreeSpace(); + }, [visible]); + + const handleRepackClick = (repack: GameRepack) => { + setRepack(repack); + setShowSelectFolderModal(true); + }; const handleFilter: React.ChangeEventHandler = (event) => { setFilteredRepacks( @@ -64,31 +69,6 @@ export function RepacksModal({ ); }; - const handleChooseDownloadsPath = async () => { - const { filePaths } = await window.electron.showOpenDialog({ - defaultPath: selectedPath, - properties: ["openDirectory"], - }); - - if (filePaths && filePaths.length > 0) { - const path = filePaths[0]; - setSelectedPath(path); - } - }; - - const handleRepackClick = (repack: GameRepack) => { - setDownloadStarting(true); - startDownload(repack.id, selectedPath).finally(() => { - setDownloadStarting(false); - }); - }; - - const getDiskFreeSpace = (path: string) => { - window.electron.getDiskFreeSpace(path).then((result) => { - setDiskFreeSpace(result); - }); - }; - return ( -
-
- - - -
-

- {t("select_folder_hint")}{" "} - - {t("hydra_settings")} - -

-
+ setShowSelectFolderModal(false)} + gameDetails={gameDetails} + startDownload={startDownload} + repack={repack} + />
@@ -140,7 +96,6 @@ export function RepacksModal({ theme="dark" onClick={() => handleRepackClick(repack)} className={styles.repackButton} - disabled={downloadStarting} >

{repack.title}

diff --git a/src/renderer/pages/game-details/select-folder-modal.css.tsx b/src/renderer/pages/game-details/select-folder-modal.css.tsx new file mode 100644 index 00000000..7d32bccc --- /dev/null +++ b/src/renderer/pages/game-details/select-folder-modal.css.tsx @@ -0,0 +1,19 @@ +import { style } from "@vanilla-extract/css"; +import { SPACING_UNIT, vars } from "@renderer/theme.css"; + +export const container = style({ + display: "flex", + flexDirection: "column", + gap: `${SPACING_UNIT * 2}px`, + width: "100%", +}); + +export const downloadsPathField = style({ + display: "flex", + gap: `${SPACING_UNIT * 2}px`, +}); + +export const hintText = style({ + fontSize: 12, + color: vars.color.bodyText, +}); diff --git a/src/renderer/pages/game-details/select-folder-modal.tsx b/src/renderer/pages/game-details/select-folder-modal.tsx new file mode 100644 index 00000000..4edfa6b1 --- /dev/null +++ b/src/renderer/pages/game-details/select-folder-modal.tsx @@ -0,0 +1,99 @@ +import { Button, Modal, TextField } from "@renderer/components"; +import { GameRepack, ShopDetails } from "@types"; +import { useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; + +import * as styles from "./select-folder-modal.css"; +import { Link } from "react-router-dom"; + +export interface SelectFolderModalProps { + visible: boolean; + gameDetails: ShopDetails; + onClose: () => void; + startDownload: (repackId: number, downloadPath: string) => Promise; + repack: GameRepack; +} + +export function SelectFolderModal({ + visible, + gameDetails, + onClose, + startDownload, + repack, +}: SelectFolderModalProps) { + const { t } = useTranslation("game_details"); + + const [selectedPath, setSelectedPath] = useState(""); + const [downloadStarting, setDownloadStarting] = useState(false); + + useEffect(() => { + Promise.all([ + window.electron.getDefaultDownloadsPath(), + window.electron.getUserPreferences(), + ]).then(([path, userPreferences]) => { + setSelectedPath(userPreferences?.downloadsPath || path); + }); + }, []); + + const handleChooseDownloadsPath = async () => { + const { filePaths } = await window.electron.showOpenDialog({ + defaultPath: selectedPath, + properties: ["openDirectory"], + }); + + if (filePaths && filePaths.length > 0) { + const path = filePaths[0]; + setSelectedPath(path); + } + }; + + const handleStartClick = () => { + setDownloadStarting(true); + startDownload(repack.id, selectedPath).finally(() => { + setDownloadStarting(false); + }); + }; + + return ( + +

+
+ + + +
+

+ {t("select_folder_hint")}{" "} + + {t("hydra_settings")} + +

+ +
+
+ ); +} From aed85671742c25b30408f8b407feadbd49093938 Mon Sep 17 00:00:00 2001 From: Hydra Date: Sun, 21 Apr 2024 22:55:00 -0300 Subject: [PATCH 018/140] Revert "feat: change selectFolderModal to a section inside repacksModal" This reverts commit 934fb1145e5ebf9ac47648dbbf5610eed1f2776f. --- src/renderer/declaration.d.ts | 2 +- .../pages/game-details/game-details.tsx | 4 + .../pages/game-details/repacks-modal.css.ts | 20 ---- .../pages/game-details/repacks-modal.tsx | 109 +++++------------- .../game-details/select-folder-modal.css.tsx | 19 +++ .../game-details/select-folder-modal.tsx | 99 ++++++++++++++++ 6 files changed, 155 insertions(+), 98 deletions(-) create mode 100644 src/renderer/pages/game-details/select-folder-modal.css.tsx create mode 100644 src/renderer/pages/game-details/select-folder-modal.tsx diff --git a/src/renderer/declaration.d.ts b/src/renderer/declaration.d.ts index 3184940a..f8d1018c 100644 --- a/src/renderer/declaration.d.ts +++ b/src/renderer/declaration.d.ts @@ -76,7 +76,7 @@ declare global { ) => Promise; /* Hardware */ - getDiskFreeSpace: (path: string) => Promise; + getDiskFreeSpace: () => Promise; /* Misc */ getOrCacheImage: (url: string) => Promise; diff --git a/src/renderer/pages/game-details/game-details.tsx b/src/renderer/pages/game-details/game-details.tsx index 9c9178bf..aae3f267 100644 --- a/src/renderer/pages/game-details/game-details.tsx +++ b/src/renderer/pages/game-details/game-details.tsx @@ -51,6 +51,7 @@ export function GameDetails() { const { t, i18n } = useTranslation("game_details"); const [showRepacksModal, setShowRepacksModal] = useState(false); + const [showSelectFolderModal, setShowSelectFolderModal] = useState(false); const randomGameObjectID = useRef(null); @@ -153,6 +154,7 @@ export function GameDetails() { ).then(() => { getGame(); setShowRepacksModal(false); + setShowSelectFolderModal(false); }); }; @@ -177,6 +179,8 @@ export function GameDetails() { visible={showRepacksModal} gameDetails={gameDetails} startDownload={handleStartDownload} + showSelectFolderModal={showSelectFolderModal} + setShowSelectFolderModal={setShowSelectFolderModal} onClose={() => setShowRepacksModal(false)} /> )} diff --git a/src/renderer/pages/game-details/repacks-modal.css.ts b/src/renderer/pages/game-details/repacks-modal.css.ts index 6a1d37f3..c2568594 100644 --- a/src/renderer/pages/game-details/repacks-modal.css.ts +++ b/src/renderer/pages/game-details/repacks-modal.css.ts @@ -16,23 +16,3 @@ export const repackButton = style({ color: vars.color.bodyText, padding: `${SPACING_UNIT * 2}px`, }); - -export const container = style({ - width: "100%", - display: "flex", - flexDirection: "column", - gap: `${SPACING_UNIT * 2}px`, - marginBottom: SPACING_UNIT * 2, - paddingBottom: SPACING_UNIT * 2, - borderBottom: `solid 1px ${vars.color.borderColor}`, -}); - -export const downloadsPathField = style({ - display: "flex", - gap: `${SPACING_UNIT * 2}px`, -}); - -export const hintText = style({ - fontSize: 12, - color: vars.color.bodyText, -}); diff --git a/src/renderer/pages/game-details/repacks-modal.tsx b/src/renderer/pages/game-details/repacks-modal.tsx index c5830de7..7908c486 100644 --- a/src/renderer/pages/game-details/repacks-modal.tsx +++ b/src/renderer/pages/game-details/repacks-modal.tsx @@ -6,16 +6,18 @@ import type { GameRepack, ShopDetails } from "@types"; import * as styles from "./repacks-modal.css"; -import { useAppSelector } from "@renderer/hooks"; -import { SPACING_UNIT } from "@renderer/theme.css"; -import { formatBytes } from "@renderer/utils"; import type { DiskSpace } from "check-disk-space"; import { format } from "date-fns"; -import { Link } from "react-router-dom"; +import { SPACING_UNIT } from "@renderer/theme.css"; +import { formatBytes } from "@renderer/utils"; +import { useAppSelector } from "@renderer/hooks"; +import { SelectFolderModal } from "./select-folder-modal"; export interface RepacksModalProps { visible: boolean; gameDetails: ShopDetails; + showSelectFolderModal: boolean; + setShowSelectFolderModal: (value: boolean) => void; startDownload: (repackId: number, downloadPath: string) => Promise; onClose: () => void; } @@ -23,13 +25,18 @@ export interface RepacksModalProps { export function RepacksModal({ visible, gameDetails, + showSelectFolderModal, + setShowSelectFolderModal, startDownload, onClose, }: RepacksModalProps) { const [diskFreeSpace, setDiskFreeSpace] = useState(null); const [filteredRepacks, setFilteredRepacks] = useState([]); - const [selectedPath, setSelectedPath] = useState(""); - const [downloadStarting, setDownloadStarting] = useState(false); + const [repack, setRepack] = useState(null); + + const repackersFriendlyNames = useAppSelector( + (state) => state.repackersFriendlyNames.value + ); const { t } = useTranslation("game_details"); @@ -37,22 +44,20 @@ export function RepacksModal({ setFilteredRepacks(gameDetails.repacks); }, [gameDetails.repacks]); - useEffect(() => { - visible && getDiskFreeSpace(selectedPath); - }, [selectedPath, visible]); - - useEffect(() => { - Promise.all([ - window.electron.getDefaultDownloadsPath(), - window.electron.getUserPreferences(), - ]).then(([path, userPreferences]) => { - setSelectedPath(userPreferences?.downloadsPath || path); + const getDiskFreeSpace = () => { + window.electron.getDiskFreeSpace().then((result) => { + setDiskFreeSpace(result); }); - }, []); + }; - const repackersFriendlyNames = useAppSelector( - (state) => state.repackersFriendlyNames.value - ); + useEffect(() => { + getDiskFreeSpace(); + }, [visible]); + + const handleRepackClick = (repack: GameRepack) => { + setRepack(repack); + setShowSelectFolderModal(true); + }; const handleFilter: React.ChangeEventHandler = (event) => { setFilteredRepacks( @@ -64,31 +69,6 @@ export function RepacksModal({ ); }; - const handleChooseDownloadsPath = async () => { - const { filePaths } = await window.electron.showOpenDialog({ - defaultPath: selectedPath, - properties: ["openDirectory"], - }); - - if (filePaths && filePaths.length > 0) { - const path = filePaths[0]; - setSelectedPath(path); - } - }; - - const handleRepackClick = (repack: GameRepack) => { - setDownloadStarting(true); - startDownload(repack.id, selectedPath).finally(() => { - setDownloadStarting(false); - }); - }; - - const getDiskFreeSpace = (path: string) => { - window.electron.getDiskFreeSpace(path).then((result) => { - setDiskFreeSpace(result); - }); - }; - return ( -
-
- - - -
-

- {t("select_folder_hint")}{" "} - - {t("hydra_settings")} - -

-
+ setShowSelectFolderModal(false)} + gameDetails={gameDetails} + startDownload={startDownload} + repack={repack} + />
@@ -140,7 +96,6 @@ export function RepacksModal({ theme="dark" onClick={() => handleRepackClick(repack)} className={styles.repackButton} - disabled={downloadStarting} >

{repack.title}

diff --git a/src/renderer/pages/game-details/select-folder-modal.css.tsx b/src/renderer/pages/game-details/select-folder-modal.css.tsx new file mode 100644 index 00000000..7d32bccc --- /dev/null +++ b/src/renderer/pages/game-details/select-folder-modal.css.tsx @@ -0,0 +1,19 @@ +import { style } from "@vanilla-extract/css"; +import { SPACING_UNIT, vars } from "@renderer/theme.css"; + +export const container = style({ + display: "flex", + flexDirection: "column", + gap: `${SPACING_UNIT * 2}px`, + width: "100%", +}); + +export const downloadsPathField = style({ + display: "flex", + gap: `${SPACING_UNIT * 2}px`, +}); + +export const hintText = style({ + fontSize: 12, + color: vars.color.bodyText, +}); diff --git a/src/renderer/pages/game-details/select-folder-modal.tsx b/src/renderer/pages/game-details/select-folder-modal.tsx new file mode 100644 index 00000000..4edfa6b1 --- /dev/null +++ b/src/renderer/pages/game-details/select-folder-modal.tsx @@ -0,0 +1,99 @@ +import { Button, Modal, TextField } from "@renderer/components"; +import { GameRepack, ShopDetails } from "@types"; +import { useEffect, useState } from "react"; +import { useTranslation } from "react-i18next"; + +import * as styles from "./select-folder-modal.css"; +import { Link } from "react-router-dom"; + +export interface SelectFolderModalProps { + visible: boolean; + gameDetails: ShopDetails; + onClose: () => void; + startDownload: (repackId: number, downloadPath: string) => Promise; + repack: GameRepack; +} + +export function SelectFolderModal({ + visible, + gameDetails, + onClose, + startDownload, + repack, +}: SelectFolderModalProps) { + const { t } = useTranslation("game_details"); + + const [selectedPath, setSelectedPath] = useState(""); + const [downloadStarting, setDownloadStarting] = useState(false); + + useEffect(() => { + Promise.all([ + window.electron.getDefaultDownloadsPath(), + window.electron.getUserPreferences(), + ]).then(([path, userPreferences]) => { + setSelectedPath(userPreferences?.downloadsPath || path); + }); + }, []); + + const handleChooseDownloadsPath = async () => { + const { filePaths } = await window.electron.showOpenDialog({ + defaultPath: selectedPath, + properties: ["openDirectory"], + }); + + if (filePaths && filePaths.length > 0) { + const path = filePaths[0]; + setSelectedPath(path); + } + }; + + const handleStartClick = () => { + setDownloadStarting(true); + startDownload(repack.id, selectedPath).finally(() => { + setDownloadStarting(false); + }); + }; + + return ( + +

+
+ + + +
+

+ {t("select_folder_hint")}{" "} + + {t("hydra_settings")} + +

+ +
+
+ ); +} From 62c92c625353be0f902d023ca804384f47933903 Mon Sep 17 00:00:00 2001 From: shadowtosser Date: Sun, 21 Apr 2024 22:57:31 -0300 Subject: [PATCH 019/140] feat: change diskFreeSpace from rapacks modal to select folder modal description --- src/locales/en/translation.json | 2 +- src/locales/pt/translation.json | 2 +- src/renderer/declaration.d.ts | 2 +- .../pages/game-details/game-details.tsx | 4 ++-- .../pages/game-details/repacks-modal.tsx | 21 +++---------------- .../game-details/select-folder-modal.tsx | 19 +++++++++++++++-- 6 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 3898ddb9..20043f54 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -79,7 +79,7 @@ "close": "Close", "playing_now": "Playing now", "change": "Change", - "select_folder_description": "Select the folder where the game will be installed", + "repacks_modal_description": "Choose the repack you want to download", "downloads_path": "Downloads path", "select_folder_hint": "To change the default folder, access the", "hydra_settings": "Hydra settings", diff --git a/src/locales/pt/translation.json b/src/locales/pt/translation.json index 110e0e71..5733059d 100644 --- a/src/locales/pt/translation.json +++ b/src/locales/pt/translation.json @@ -75,7 +75,7 @@ "deleting": "Excluindo instalador…", "playing_now": "Jogando agora", "change": "Mudar", - "select_folder_description": "Selecione a pasta em que o jogo será baixado", + "repacks_modal_description": "Escolha o repack do jogo que deseja baixar", "downloads_path": "Diretório do download", "select_folder_hint": "Para trocar a pasta padrão, acesse as ", "hydra_settings": "Configurações do Hydra", diff --git a/src/renderer/declaration.d.ts b/src/renderer/declaration.d.ts index f8d1018c..3184940a 100644 --- a/src/renderer/declaration.d.ts +++ b/src/renderer/declaration.d.ts @@ -76,7 +76,7 @@ declare global { ) => Promise; /* Hardware */ - getDiskFreeSpace: () => Promise; + getDiskFreeSpace: (path: string) => Promise; /* Misc */ getOrCacheImage: (url: string) => Promise; diff --git a/src/renderer/pages/game-details/game-details.tsx b/src/renderer/pages/game-details/game-details.tsx index aae3f267..7f744198 100644 --- a/src/renderer/pages/game-details/game-details.tsx +++ b/src/renderer/pages/game-details/game-details.tsx @@ -19,15 +19,15 @@ import { useAppDispatch, useDownload } from "@renderer/hooks"; import starsAnimation from "@renderer/assets/lottie/stars.json"; import { vars } from "@renderer/theme.css"; +import Lottie from "lottie-react"; import { useTranslation } from "react-i18next"; import { SkeletonTheme } from "react-loading-skeleton"; +import { DescriptionHeader } from "./description-header"; import { GameDetailsSkeleton } from "./game-details-skeleton"; import * as styles from "./game-details.css"; import { HeroPanel } from "./hero-panel"; import { HowLongToBeatSection } from "./how-long-to-beat-section"; import { RepacksModal } from "./repacks-modal"; -import Lottie from "lottie-react"; -import { DescriptionHeader } from "./description-header"; export function GameDetails() { const { objectID, shop } = useParams(); diff --git a/src/renderer/pages/game-details/repacks-modal.tsx b/src/renderer/pages/game-details/repacks-modal.tsx index 7908c486..3e240461 100644 --- a/src/renderer/pages/game-details/repacks-modal.tsx +++ b/src/renderer/pages/game-details/repacks-modal.tsx @@ -6,11 +6,9 @@ import type { GameRepack, ShopDetails } from "@types"; import * as styles from "./repacks-modal.css"; -import type { DiskSpace } from "check-disk-space"; -import { format } from "date-fns"; -import { SPACING_UNIT } from "@renderer/theme.css"; -import { formatBytes } from "@renderer/utils"; import { useAppSelector } from "@renderer/hooks"; +import { SPACING_UNIT } from "@renderer/theme.css"; +import { format } from "date-fns"; import { SelectFolderModal } from "./select-folder-modal"; export interface RepacksModalProps { @@ -30,7 +28,6 @@ export function RepacksModal({ startDownload, onClose, }: RepacksModalProps) { - const [diskFreeSpace, setDiskFreeSpace] = useState(null); const [filteredRepacks, setFilteredRepacks] = useState([]); const [repack, setRepack] = useState(null); @@ -44,16 +41,6 @@ export function RepacksModal({ setFilteredRepacks(gameDetails.repacks); }, [gameDetails.repacks]); - const getDiskFreeSpace = () => { - window.electron.getDiskFreeSpace().then((result) => { - setDiskFreeSpace(result); - }); - }; - - useEffect(() => { - getDiskFreeSpace(); - }, [visible]); - const handleRepackClick = (repack: GameRepack) => { setRepack(repack); setShowSelectFolderModal(true); @@ -73,9 +60,7 @@ export function RepacksModal({ (null); const [selectedPath, setSelectedPath] = useState(""); const [downloadStarting, setDownloadStarting] = useState(false); + useEffect(() => { + visible && getDiskFreeSpace(selectedPath); + }, [visible, selectedPath]); + useEffect(() => { Promise.all([ window.electron.getDefaultDownloadsPath(), @@ -35,6 +42,12 @@ export function SelectFolderModal({ }); }, []); + const getDiskFreeSpace = (path: string) => { + window.electron.getDiskFreeSpace(path).then((result) => { + setDiskFreeSpace(result); + }); + }; + const handleChooseDownloadsPath = async () => { const { filePaths } = await window.electron.showOpenDialog({ defaultPath: selectedPath, @@ -58,7 +71,9 @@ export function SelectFolderModal({
From d488a9858d981a55ad9d1790ad36462eea47eb1a Mon Sep 17 00:00:00 2001 From: Hydra Date: Sun, 21 Apr 2024 22:57:31 -0300 Subject: [PATCH 020/140] feat: change diskFreeSpace from rapacks modal to select folder modal description --- src/locales/en/translation.json | 2 +- src/locales/pt/translation.json | 2 +- src/renderer/declaration.d.ts | 2 +- .../pages/game-details/game-details.tsx | 4 ++-- .../pages/game-details/repacks-modal.tsx | 21 +++---------------- .../game-details/select-folder-modal.tsx | 19 +++++++++++++++-- 6 files changed, 25 insertions(+), 25 deletions(-) diff --git a/src/locales/en/translation.json b/src/locales/en/translation.json index 3898ddb9..20043f54 100644 --- a/src/locales/en/translation.json +++ b/src/locales/en/translation.json @@ -79,7 +79,7 @@ "close": "Close", "playing_now": "Playing now", "change": "Change", - "select_folder_description": "Select the folder where the game will be installed", + "repacks_modal_description": "Choose the repack you want to download", "downloads_path": "Downloads path", "select_folder_hint": "To change the default folder, access the", "hydra_settings": "Hydra settings", diff --git a/src/locales/pt/translation.json b/src/locales/pt/translation.json index 110e0e71..5733059d 100644 --- a/src/locales/pt/translation.json +++ b/src/locales/pt/translation.json @@ -75,7 +75,7 @@ "deleting": "Excluindo instalador…", "playing_now": "Jogando agora", "change": "Mudar", - "select_folder_description": "Selecione a pasta em que o jogo será baixado", + "repacks_modal_description": "Escolha o repack do jogo que deseja baixar", "downloads_path": "Diretório do download", "select_folder_hint": "Para trocar a pasta padrão, acesse as ", "hydra_settings": "Configurações do Hydra", diff --git a/src/renderer/declaration.d.ts b/src/renderer/declaration.d.ts index f8d1018c..3184940a 100644 --- a/src/renderer/declaration.d.ts +++ b/src/renderer/declaration.d.ts @@ -76,7 +76,7 @@ declare global { ) => Promise; /* Hardware */ - getDiskFreeSpace: () => Promise; + getDiskFreeSpace: (path: string) => Promise; /* Misc */ getOrCacheImage: (url: string) => Promise; diff --git a/src/renderer/pages/game-details/game-details.tsx b/src/renderer/pages/game-details/game-details.tsx index aae3f267..7f744198 100644 --- a/src/renderer/pages/game-details/game-details.tsx +++ b/src/renderer/pages/game-details/game-details.tsx @@ -19,15 +19,15 @@ import { useAppDispatch, useDownload } from "@renderer/hooks"; import starsAnimation from "@renderer/assets/lottie/stars.json"; import { vars } from "@renderer/theme.css"; +import Lottie from "lottie-react"; import { useTranslation } from "react-i18next"; import { SkeletonTheme } from "react-loading-skeleton"; +import { DescriptionHeader } from "./description-header"; import { GameDetailsSkeleton } from "./game-details-skeleton"; import * as styles from "./game-details.css"; import { HeroPanel } from "./hero-panel"; import { HowLongToBeatSection } from "./how-long-to-beat-section"; import { RepacksModal } from "./repacks-modal"; -import Lottie from "lottie-react"; -import { DescriptionHeader } from "./description-header"; export function GameDetails() { const { objectID, shop } = useParams(); diff --git a/src/renderer/pages/game-details/repacks-modal.tsx b/src/renderer/pages/game-details/repacks-modal.tsx index 7908c486..3e240461 100644 --- a/src/renderer/pages/game-details/repacks-modal.tsx +++ b/src/renderer/pages/game-details/repacks-modal.tsx @@ -6,11 +6,9 @@ import type { GameRepack, ShopDetails } from "@types"; import * as styles from "./repacks-modal.css"; -import type { DiskSpace } from "check-disk-space"; -import { format } from "date-fns"; -import { SPACING_UNIT } from "@renderer/theme.css"; -import { formatBytes } from "@renderer/utils"; import { useAppSelector } from "@renderer/hooks"; +import { SPACING_UNIT } from "@renderer/theme.css"; +import { format } from "date-fns"; import { SelectFolderModal } from "./select-folder-modal"; export interface RepacksModalProps { @@ -30,7 +28,6 @@ export function RepacksModal({ startDownload, onClose, }: RepacksModalProps) { - const [diskFreeSpace, setDiskFreeSpace] = useState(null); const [filteredRepacks, setFilteredRepacks] = useState([]); const [repack, setRepack] = useState(null); @@ -44,16 +41,6 @@ export function RepacksModal({ setFilteredRepacks(gameDetails.repacks); }, [gameDetails.repacks]); - const getDiskFreeSpace = () => { - window.electron.getDiskFreeSpace().then((result) => { - setDiskFreeSpace(result); - }); - }; - - useEffect(() => { - getDiskFreeSpace(); - }, [visible]); - const handleRepackClick = (repack: GameRepack) => { setRepack(repack); setShowSelectFolderModal(true); @@ -73,9 +60,7 @@ export function RepacksModal({ (null); const [selectedPath, setSelectedPath] = useState(""); const [downloadStarting, setDownloadStarting] = useState(false); + useEffect(() => { + visible && getDiskFreeSpace(selectedPath); + }, [visible, selectedPath]); + useEffect(() => { Promise.all([ window.electron.getDefaultDownloadsPath(), @@ -35,6 +42,12 @@ export function SelectFolderModal({ }); }, []); + const getDiskFreeSpace = (path: string) => { + window.electron.getDiskFreeSpace(path).then((result) => { + setDiskFreeSpace(result); + }); + }; + const handleChooseDownloadsPath = async () => { const { filePaths } = await window.electron.showOpenDialog({ defaultPath: selectedPath, @@ -58,7 +71,9 @@ export function SelectFolderModal({
From aadea11f28372e241746a19a375813e709aa1cee Mon Sep 17 00:00:00 2001 From: shadowtosser Date: Sun, 21 Apr 2024 22:59:03 -0300 Subject: [PATCH 021/140] fix: disable change path button when downloading is starting --- src/renderer/pages/game-details/select-folder-modal.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/renderer/pages/game-details/select-folder-modal.tsx b/src/renderer/pages/game-details/select-folder-modal.tsx index 5799600c..d37271c8 100644 --- a/src/renderer/pages/game-details/select-folder-modal.tsx +++ b/src/renderer/pages/game-details/select-folder-modal.tsx @@ -89,6 +89,7 @@ export function SelectFolderModal({ style={{ alignSelf: "flex-end" }} theme="outline" onClick={handleChooseDownloadsPath} + disabled={downloadStarting} > {t("change")} From 0f60f5ca83ffe8950f39880f8add0c41463c9ce8 Mon Sep 17 00:00:00 2001 From: Hydra Date: Sun, 21 Apr 2024 22:59:03 -0300 Subject: [PATCH 022/140] fix: disable change path button when downloading is starting --- src/renderer/pages/game-details/select-folder-modal.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/renderer/pages/game-details/select-folder-modal.tsx b/src/renderer/pages/game-details/select-folder-modal.tsx index 5799600c..d37271c8 100644 --- a/src/renderer/pages/game-details/select-folder-modal.tsx +++ b/src/renderer/pages/game-details/select-folder-modal.tsx @@ -89,6 +89,7 @@ export function SelectFolderModal({ style={{ alignSelf: "flex-end" }} theme="outline" onClick={handleChooseDownloadsPath} + disabled={downloadStarting} > {t("change")} From d7ab50846d0ecb35f6813999970255f5b69bb3e4 Mon Sep 17 00:00:00 2001 From: Fernando Zanutto Date: Tue, 23 Apr 2024 09:34:07 -0300 Subject: [PATCH 023/140] feat: close modal on Esc press --- src/renderer/components/modal/modal.tsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/renderer/components/modal/modal.tsx b/src/renderer/components/modal/modal.tsx index 35be1bf9..4586a741 100644 --- a/src/renderer/components/modal/modal.tsx +++ b/src/renderer/components/modal/modal.tsx @@ -38,6 +38,16 @@ export function Modal({ }); }; + useEffect(() => { + const close = (e: KeyboardEvent) => { + if (e.key === "Escape") { + handleCloseClick(); + } + }; + window.addEventListener("keydown", close); + return () => window.removeEventListener("keydown", close); + }, []); + useEffect(() => { dispatch(toggleDragging(visible)); }, [dispatch, visible]); From dbdb36999df1628ee9fd708e411a17f990cb12e7 Mon Sep 17 00:00:00 2001 From: Fernando Zanutto Date: Tue, 23 Apr 2024 09:34:07 -0300 Subject: [PATCH 024/140] feat: close modal on Esc press --- src/renderer/components/modal/modal.tsx | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/renderer/components/modal/modal.tsx b/src/renderer/components/modal/modal.tsx index 35be1bf9..4586a741 100644 --- a/src/renderer/components/modal/modal.tsx +++ b/src/renderer/components/modal/modal.tsx @@ -38,6 +38,16 @@ export function Modal({ }); }; + useEffect(() => { + const close = (e: KeyboardEvent) => { + if (e.key === "Escape") { + handleCloseClick(); + } + }; + window.addEventListener("keydown", close); + return () => window.removeEventListener("keydown", close); + }, []); + useEffect(() => { dispatch(toggleDragging(visible)); }, [dispatch, visible]); From a614d2497612815dcd9f2c0f2ad47eabce9d5864 Mon Sep 17 00:00:00 2001 From: Fernando Zanutto Date: Tue, 23 Apr 2024 15:01:02 -0300 Subject: [PATCH 025/140] feat: correctly check if modal is top most modal --- src/renderer/components/modal/modal.tsx | 46 +++++++++++++++++++++---- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/src/renderer/components/modal/modal.tsx b/src/renderer/components/modal/modal.tsx index 4586a741..38236fb6 100644 --- a/src/renderer/components/modal/modal.tsx +++ b/src/renderer/components/modal/modal.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react"; +import { useEffect, useId, useState } from "react"; import { createPortal } from "react-dom"; import { XIcon } from "@primer/octicons-react"; @@ -23,6 +23,7 @@ export function Modal({ }: ModalProps) { const [isClosing, setIsClosing] = useState(false); const dispatch = useAppDispatch(); + const componentId = useId(); const handleCloseClick = () => { setIsClosing(true); @@ -38,14 +39,39 @@ export function Modal({ }); }; + const isTopMostModal = () => { + const openModals = document.getElementsByClassName("modal-container"); + return openModals.length && openModals[openModals.length - 1].id === componentId; + }; + useEffect(() => { - const close = (e: KeyboardEvent) => { - if (e.key === "Escape") { + const onKeyDown = (e: KeyboardEvent) => { + if (e.key === "Escape" && isTopMostModal()) { handleCloseClick(); } }; - window.addEventListener("keydown", close); - return () => window.removeEventListener("keydown", close); + + window.addEventListener("keydown", onKeyDown, false); + return () => window.removeEventListener("keydown", onKeyDown, false); + }, []); + + useEffect(() => { + const onMouseUp = (e: MouseEvent) => { + if (!isTopMostModal()) return; + + const modalContent = document.getElementById( + "modal-content-" + componentId + ); + + const clickInsideContent = modalContent.contains(e.target as Node); + + if (!clickInsideContent) { + handleCloseClick(); + } + }; + + window.addEventListener("mousedown", onMouseUp); + return () => window.removeEventListener("mousedown", onMouseUp); }, []); useEffect(() => { @@ -55,8 +81,14 @@ export function Modal({ if (!visible) return null; return createPortal( -
-
+
+

{title}

From f8947d4f496fb30cbc4b25030e1156feeef6f868 Mon Sep 17 00:00:00 2001 From: Fernando Zanutto Date: Tue, 23 Apr 2024 15:01:02 -0300 Subject: [PATCH 026/140] feat: correctly check if modal is top most modal --- src/renderer/components/modal/modal.tsx | 46 +++++++++++++++++++++---- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/src/renderer/components/modal/modal.tsx b/src/renderer/components/modal/modal.tsx index 4586a741..38236fb6 100644 --- a/src/renderer/components/modal/modal.tsx +++ b/src/renderer/components/modal/modal.tsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react"; +import { useEffect, useId, useState } from "react"; import { createPortal } from "react-dom"; import { XIcon } from "@primer/octicons-react"; @@ -23,6 +23,7 @@ export function Modal({ }: ModalProps) { const [isClosing, setIsClosing] = useState(false); const dispatch = useAppDispatch(); + const componentId = useId(); const handleCloseClick = () => { setIsClosing(true); @@ -38,14 +39,39 @@ export function Modal({ }); }; + const isTopMostModal = () => { + const openModals = document.getElementsByClassName("modal-container"); + return openModals.length && openModals[openModals.length - 1].id === componentId; + }; + useEffect(() => { - const close = (e: KeyboardEvent) => { - if (e.key === "Escape") { + const onKeyDown = (e: KeyboardEvent) => { + if (e.key === "Escape" && isTopMostModal()) { handleCloseClick(); } }; - window.addEventListener("keydown", close); - return () => window.removeEventListener("keydown", close); + + window.addEventListener("keydown", onKeyDown, false); + return () => window.removeEventListener("keydown", onKeyDown, false); + }, []); + + useEffect(() => { + const onMouseUp = (e: MouseEvent) => { + if (!isTopMostModal()) return; + + const modalContent = document.getElementById( + "modal-content-" + componentId + ); + + const clickInsideContent = modalContent.contains(e.target as Node); + + if (!clickInsideContent) { + handleCloseClick(); + } + }; + + window.addEventListener("mousedown", onMouseUp); + return () => window.removeEventListener("mousedown", onMouseUp); }, []); useEffect(() => { @@ -55,8 +81,14 @@ export function Modal({ if (!visible) return null; return createPortal( -
-
+
+

{title}

From e28dfcad838f8bedc928ae8a5f1b8deb959a4503 Mon Sep 17 00:00:00 2001 From: Fernando Zanutto Date: Tue, 23 Apr 2024 15:04:22 -0300 Subject: [PATCH 027/140] feat: apply prettier and rename variable --- src/renderer/components/modal/modal.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/renderer/components/modal/modal.tsx b/src/renderer/components/modal/modal.tsx index 38236fb6..e6ab2973 100644 --- a/src/renderer/components/modal/modal.tsx +++ b/src/renderer/components/modal/modal.tsx @@ -41,7 +41,9 @@ export function Modal({ const isTopMostModal = () => { const openModals = document.getElementsByClassName("modal-container"); - return openModals.length && openModals[openModals.length - 1].id === componentId; + return ( + openModals.length && openModals[openModals.length - 1].id === componentId + ); }; useEffect(() => { @@ -63,9 +65,9 @@ export function Modal({ "modal-content-" + componentId ); - const clickInsideContent = modalContent.contains(e.target as Node); + const clickedOutsideContent = !modalContent.contains(e.target as Node); - if (!clickInsideContent) { + if (clickedOutsideContent) { handleCloseClick(); } }; From 67af138e5af473babf6ac34adbb623cf39242bf2 Mon Sep 17 00:00:00 2001 From: Fernando Zanutto Date: Tue, 23 Apr 2024 15:04:22 -0300 Subject: [PATCH 028/140] feat: apply prettier and rename variable --- src/renderer/components/modal/modal.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/renderer/components/modal/modal.tsx b/src/renderer/components/modal/modal.tsx index 38236fb6..e6ab2973 100644 --- a/src/renderer/components/modal/modal.tsx +++ b/src/renderer/components/modal/modal.tsx @@ -41,7 +41,9 @@ export function Modal({ const isTopMostModal = () => { const openModals = document.getElementsByClassName("modal-container"); - return openModals.length && openModals[openModals.length - 1].id === componentId; + return ( + openModals.length && openModals[openModals.length - 1].id === componentId + ); }; useEffect(() => { @@ -63,9 +65,9 @@ export function Modal({ "modal-content-" + componentId ); - const clickInsideContent = modalContent.contains(e.target as Node); + const clickedOutsideContent = !modalContent.contains(e.target as Node); - if (!clickInsideContent) { + if (clickedOutsideContent) { handleCloseClick(); } }; From fd50e3e30b1703289bdb5484a7fd4c95063e595c Mon Sep 17 00:00:00 2001 From: Fernando Zanutto Date: Tue, 23 Apr 2024 15:07:31 -0300 Subject: [PATCH 029/140] feat: rename modal container id --- src/renderer/components/modal/modal.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/renderer/components/modal/modal.tsx b/src/renderer/components/modal/modal.tsx index e6ab2973..0f15a0de 100644 --- a/src/renderer/components/modal/modal.tsx +++ b/src/renderer/components/modal/modal.tsx @@ -42,7 +42,8 @@ export function Modal({ const isTopMostModal = () => { const openModals = document.getElementsByClassName("modal-container"); return ( - openModals.length && openModals[openModals.length - 1].id === componentId + openModals.length && + openModals[openModals.length - 1].id === "modal-container-" + componentId ); }; @@ -85,7 +86,7 @@ export function Modal({ return createPortal(
Date: Tue, 23 Apr 2024 15:07:31 -0300 Subject: [PATCH 030/140] feat: rename modal container id --- src/renderer/components/modal/modal.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/renderer/components/modal/modal.tsx b/src/renderer/components/modal/modal.tsx index e6ab2973..0f15a0de 100644 --- a/src/renderer/components/modal/modal.tsx +++ b/src/renderer/components/modal/modal.tsx @@ -42,7 +42,8 @@ export function Modal({ const isTopMostModal = () => { const openModals = document.getElementsByClassName("modal-container"); return ( - openModals.length && openModals[openModals.length - 1].id === componentId + openModals.length && + openModals[openModals.length - 1].id === "modal-container-" + componentId ); }; @@ -85,7 +86,7 @@ export function Modal({ return createPortal(
Date: Tue, 23 Apr 2024 15:47:10 -0300 Subject: [PATCH 031/140] feat: use role attribute instead of using class with no style --- src/renderer/components/modal/modal.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/renderer/components/modal/modal.tsx b/src/renderer/components/modal/modal.tsx index 0f15a0de..6cd417dd 100644 --- a/src/renderer/components/modal/modal.tsx +++ b/src/renderer/components/modal/modal.tsx @@ -40,7 +40,7 @@ export function Modal({ }; const isTopMostModal = () => { - const openModals = document.getElementsByClassName("modal-container"); + const openModals = document.querySelectorAll("[role=modal-container]"); return ( openModals.length && openModals[openModals.length - 1].id === "modal-container-" + componentId @@ -85,7 +85,8 @@ export function Modal({ return createPortal(
Date: Tue, 23 Apr 2024 15:47:10 -0300 Subject: [PATCH 032/140] feat: use role attribute instead of using class with no style --- src/renderer/components/modal/modal.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/renderer/components/modal/modal.tsx b/src/renderer/components/modal/modal.tsx index 0f15a0de..6cd417dd 100644 --- a/src/renderer/components/modal/modal.tsx +++ b/src/renderer/components/modal/modal.tsx @@ -40,7 +40,7 @@ export function Modal({ }; const isTopMostModal = () => { - const openModals = document.getElementsByClassName("modal-container"); + const openModals = document.querySelectorAll("[role=modal-container]"); return ( openModals.length && openModals[openModals.length - 1].id === "modal-container-" + componentId @@ -85,7 +85,8 @@ export function Modal({ return createPortal(
Date: Tue, 23 Apr 2024 15:47:34 -0300 Subject: [PATCH 033/140] feat: rename function --- src/renderer/components/modal/modal.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/renderer/components/modal/modal.tsx b/src/renderer/components/modal/modal.tsx index 6cd417dd..eed46253 100644 --- a/src/renderer/components/modal/modal.tsx +++ b/src/renderer/components/modal/modal.tsx @@ -59,7 +59,7 @@ export function Modal({ }, []); useEffect(() => { - const onMouseUp = (e: MouseEvent) => { + const onMouseDown = (e: MouseEvent) => { if (!isTopMostModal()) return; const modalContent = document.getElementById( @@ -73,8 +73,8 @@ export function Modal({ } }; - window.addEventListener("mousedown", onMouseUp); - return () => window.removeEventListener("mousedown", onMouseUp); + window.addEventListener("mousedown", onMouseDown); + return () => window.removeEventListener("mousedown", onMouseDown); }, []); useEffect(() => { From d1ad0ea31b0e304e8c4f42ef2633e4e5d31ba9d2 Mon Sep 17 00:00:00 2001 From: Fernando Zanutto Date: Tue, 23 Apr 2024 15:47:34 -0300 Subject: [PATCH 034/140] feat: rename function --- src/renderer/components/modal/modal.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/renderer/components/modal/modal.tsx b/src/renderer/components/modal/modal.tsx index 6cd417dd..eed46253 100644 --- a/src/renderer/components/modal/modal.tsx +++ b/src/renderer/components/modal/modal.tsx @@ -59,7 +59,7 @@ export function Modal({ }, []); useEffect(() => { - const onMouseUp = (e: MouseEvent) => { + const onMouseDown = (e: MouseEvent) => { if (!isTopMostModal()) return; const modalContent = document.getElementById( @@ -73,8 +73,8 @@ export function Modal({ } }; - window.addEventListener("mousedown", onMouseUp); - return () => window.removeEventListener("mousedown", onMouseUp); + window.addEventListener("mousedown", onMouseDown); + return () => window.removeEventListener("mousedown", onMouseDown); }, []); useEffect(() => { From 0f064ca8e6da96f2d9f0249bfb3a24bc2c606629 Mon Sep 17 00:00:00 2001 From: Fernando Zanutto Date: Tue, 23 Apr 2024 15:48:00 -0300 Subject: [PATCH 035/140] feat: useRef instead of getting element by id --- src/renderer/components/modal/modal.tsx | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/renderer/components/modal/modal.tsx b/src/renderer/components/modal/modal.tsx index eed46253..2b31998b 100644 --- a/src/renderer/components/modal/modal.tsx +++ b/src/renderer/components/modal/modal.tsx @@ -1,4 +1,4 @@ -import { useEffect, useId, useState } from "react"; +import { useEffect, useId, useRef, useState } from "react"; import { createPortal } from "react-dom"; import { XIcon } from "@primer/octicons-react"; @@ -23,6 +23,7 @@ export function Modal({ }: ModalProps) { const [isClosing, setIsClosing] = useState(false); const dispatch = useAppDispatch(); + const modalContentRef = useRef(null); const componentId = useId(); const handleCloseClick = () => { @@ -54,19 +55,15 @@ export function Modal({ } }; - window.addEventListener("keydown", onKeyDown, false); - return () => window.removeEventListener("keydown", onKeyDown, false); + window.addEventListener("keydown", onKeyDown); + return () => window.removeEventListener("keydown", onKeyDown); }, []); useEffect(() => { const onMouseDown = (e: MouseEvent) => { if (!isTopMostModal()) return; - const modalContent = document.getElementById( - "modal-content-" + componentId - ); - - const clickedOutsideContent = !modalContent.contains(e.target as Node); + const clickedOutsideContent = !modalContentRef.current.contains(e.target as Node); if (clickedOutsideContent) { handleCloseClick(); @@ -91,7 +88,7 @@ export function Modal({ >
From d9c6d8704db66073ec802ffe99d7d93939f2890a Mon Sep 17 00:00:00 2001 From: Fernando Zanutto Date: Tue, 23 Apr 2024 15:48:00 -0300 Subject: [PATCH 036/140] feat: useRef instead of getting element by id --- src/renderer/components/modal/modal.tsx | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/renderer/components/modal/modal.tsx b/src/renderer/components/modal/modal.tsx index eed46253..2b31998b 100644 --- a/src/renderer/components/modal/modal.tsx +++ b/src/renderer/components/modal/modal.tsx @@ -1,4 +1,4 @@ -import { useEffect, useId, useState } from "react"; +import { useEffect, useId, useRef, useState } from "react"; import { createPortal } from "react-dom"; import { XIcon } from "@primer/octicons-react"; @@ -23,6 +23,7 @@ export function Modal({ }: ModalProps) { const [isClosing, setIsClosing] = useState(false); const dispatch = useAppDispatch(); + const modalContentRef = useRef(null); const componentId = useId(); const handleCloseClick = () => { @@ -54,19 +55,15 @@ export function Modal({ } }; - window.addEventListener("keydown", onKeyDown, false); - return () => window.removeEventListener("keydown", onKeyDown, false); + window.addEventListener("keydown", onKeyDown); + return () => window.removeEventListener("keydown", onKeyDown); }, []); useEffect(() => { const onMouseDown = (e: MouseEvent) => { if (!isTopMostModal()) return; - const modalContent = document.getElementById( - "modal-content-" + componentId - ); - - const clickedOutsideContent = !modalContent.contains(e.target as Node); + const clickedOutsideContent = !modalContentRef.current.contains(e.target as Node); if (clickedOutsideContent) { handleCloseClick(); @@ -91,7 +88,7 @@ export function Modal({ >
From 1aa0c215a8f6954a9b50dec7e7a7b9f6e76f554e Mon Sep 17 00:00:00 2001 From: Fernando Zanutto Date: Tue, 23 Apr 2024 19:11:38 -0300 Subject: [PATCH 037/140] feat: removing necessity of id on outer div --- src/renderer/components/modal/modal.tsx | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/renderer/components/modal/modal.tsx b/src/renderer/components/modal/modal.tsx index 2b31998b..a1cfb087 100644 --- a/src/renderer/components/modal/modal.tsx +++ b/src/renderer/components/modal/modal.tsx @@ -41,10 +41,10 @@ export function Modal({ }; const isTopMostModal = () => { - const openModals = document.querySelectorAll("[role=modal-container]"); + const openModals = document.querySelectorAll("[role=modal-content]"); return ( openModals.length && - openModals[openModals.length - 1].id === "modal-container-" + componentId + openModals[openModals.length - 1] === modalContentRef.current ); }; @@ -63,7 +63,9 @@ export function Modal({ const onMouseDown = (e: MouseEvent) => { if (!isTopMostModal()) return; - const clickedOutsideContent = !modalContentRef.current.contains(e.target as Node); + const clickedOutsideContent = !modalContentRef.current.contains( + e.target as Node + ); if (clickedOutsideContent) { handleCloseClick(); @@ -81,13 +83,10 @@ export function Modal({ if (!visible) return null; return createPortal( -
+
From c1055463cce84c16e06f2eaea13ffe10c889aa6a Mon Sep 17 00:00:00 2001 From: Fernando Zanutto Date: Tue, 23 Apr 2024 19:11:38 -0300 Subject: [PATCH 038/140] feat: removing necessity of id on outer div --- src/renderer/components/modal/modal.tsx | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/renderer/components/modal/modal.tsx b/src/renderer/components/modal/modal.tsx index 2b31998b..a1cfb087 100644 --- a/src/renderer/components/modal/modal.tsx +++ b/src/renderer/components/modal/modal.tsx @@ -41,10 +41,10 @@ export function Modal({ }; const isTopMostModal = () => { - const openModals = document.querySelectorAll("[role=modal-container]"); + const openModals = document.querySelectorAll("[role=modal-content]"); return ( openModals.length && - openModals[openModals.length - 1].id === "modal-container-" + componentId + openModals[openModals.length - 1] === modalContentRef.current ); }; @@ -63,7 +63,9 @@ export function Modal({ const onMouseDown = (e: MouseEvent) => { if (!isTopMostModal()) return; - const clickedOutsideContent = !modalContentRef.current.contains(e.target as Node); + const clickedOutsideContent = !modalContentRef.current.contains( + e.target as Node + ); if (clickedOutsideContent) { handleCloseClick(); @@ -81,13 +83,10 @@ export function Modal({ if (!visible) return null; return createPortal( -
+
From 1deb435b4233a588ea9802acdb2921ece69c3da1 Mon Sep 17 00:00:00 2001 From: Fernando Zanutto Date: Tue, 23 Apr 2024 19:15:26 -0300 Subject: [PATCH 039/140] feat: rename role --- src/renderer/components/modal/modal.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/renderer/components/modal/modal.tsx b/src/renderer/components/modal/modal.tsx index a1cfb087..cc75db26 100644 --- a/src/renderer/components/modal/modal.tsx +++ b/src/renderer/components/modal/modal.tsx @@ -41,7 +41,7 @@ export function Modal({ }; const isTopMostModal = () => { - const openModals = document.querySelectorAll("[role=modal-content]"); + const openModals = document.querySelectorAll("[role=modal]"); return ( openModals.length && openModals[openModals.length - 1] === modalContentRef.current @@ -86,7 +86,7 @@ export function Modal({
From 5bcce3eca22eb62f38e3a7293a61bd77adb639b6 Mon Sep 17 00:00:00 2001 From: Fernando Zanutto Date: Tue, 23 Apr 2024 19:15:26 -0300 Subject: [PATCH 040/140] feat: rename role --- src/renderer/components/modal/modal.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/renderer/components/modal/modal.tsx b/src/renderer/components/modal/modal.tsx index a1cfb087..cc75db26 100644 --- a/src/renderer/components/modal/modal.tsx +++ b/src/renderer/components/modal/modal.tsx @@ -41,7 +41,7 @@ export function Modal({ }; const isTopMostModal = () => { - const openModals = document.querySelectorAll("[role=modal-content]"); + const openModals = document.querySelectorAll("[role=modal]"); return ( openModals.length && openModals[openModals.length - 1] === modalContentRef.current @@ -86,7 +86,7 @@ export function Modal({
From 981b7266a373ebf630f0a5298f8714c48c3c7e7d Mon Sep 17 00:00:00 2001 From: Fernando Zanutto Date: Tue, 23 Apr 2024 19:25:47 -0300 Subject: [PATCH 041/140] fix: add handleCloseClick to useEffect dependency --- src/renderer/components/modal/modal.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/renderer/components/modal/modal.tsx b/src/renderer/components/modal/modal.tsx index cc75db26..f2575e1f 100644 --- a/src/renderer/components/modal/modal.tsx +++ b/src/renderer/components/modal/modal.tsx @@ -57,7 +57,7 @@ export function Modal({ window.addEventListener("keydown", onKeyDown); return () => window.removeEventListener("keydown", onKeyDown); - }, []); + }, [handleCloseClick]); useEffect(() => { const onMouseDown = (e: MouseEvent) => { @@ -74,7 +74,7 @@ export function Modal({ window.addEventListener("mousedown", onMouseDown); return () => window.removeEventListener("mousedown", onMouseDown); - }, []); + }, [handleCloseClick]); useEffect(() => { dispatch(toggleDragging(visible)); From 01c66d79afb8ff24255f593ca20ec4ac88f4b340 Mon Sep 17 00:00:00 2001 From: Fernando Zanutto Date: Tue, 23 Apr 2024 19:25:47 -0300 Subject: [PATCH 042/140] fix: add handleCloseClick to useEffect dependency --- src/renderer/components/modal/modal.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/renderer/components/modal/modal.tsx b/src/renderer/components/modal/modal.tsx index cc75db26..f2575e1f 100644 --- a/src/renderer/components/modal/modal.tsx +++ b/src/renderer/components/modal/modal.tsx @@ -57,7 +57,7 @@ export function Modal({ window.addEventListener("keydown", onKeyDown); return () => window.removeEventListener("keydown", onKeyDown); - }, []); + }, [handleCloseClick]); useEffect(() => { const onMouseDown = (e: MouseEvent) => { @@ -74,7 +74,7 @@ export function Modal({ window.addEventListener("mousedown", onMouseDown); return () => window.removeEventListener("mousedown", onMouseDown); - }, []); + }, [handleCloseClick]); useEffect(() => { dispatch(toggleDragging(visible)); From 9a73be47c4e8c542d0128d4ac3b9fee675b40afb Mon Sep 17 00:00:00 2001 From: Fernando Zanutto Date: Tue, 23 Apr 2024 19:28:32 -0300 Subject: [PATCH 043/140] fix: remove unused variable --- src/renderer/components/modal/modal.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/renderer/components/modal/modal.tsx b/src/renderer/components/modal/modal.tsx index f2575e1f..288930e3 100644 --- a/src/renderer/components/modal/modal.tsx +++ b/src/renderer/components/modal/modal.tsx @@ -1,4 +1,4 @@ -import { useEffect, useId, useRef, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { createPortal } from "react-dom"; import { XIcon } from "@primer/octicons-react"; @@ -24,7 +24,6 @@ export function Modal({ const [isClosing, setIsClosing] = useState(false); const dispatch = useAppDispatch(); const modalContentRef = useRef(null); - const componentId = useId(); const handleCloseClick = () => { setIsClosing(true); From 7ba7391c833c145f5d7709afefbc342182a39763 Mon Sep 17 00:00:00 2001 From: Fernando Zanutto Date: Tue, 23 Apr 2024 19:28:32 -0300 Subject: [PATCH 044/140] fix: remove unused variable --- src/renderer/components/modal/modal.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/renderer/components/modal/modal.tsx b/src/renderer/components/modal/modal.tsx index f2575e1f..288930e3 100644 --- a/src/renderer/components/modal/modal.tsx +++ b/src/renderer/components/modal/modal.tsx @@ -1,4 +1,4 @@ -import { useEffect, useId, useRef, useState } from "react"; +import { useEffect, useRef, useState } from "react"; import { createPortal } from "react-dom"; import { XIcon } from "@primer/octicons-react"; @@ -24,7 +24,6 @@ export function Modal({ const [isClosing, setIsClosing] = useState(false); const dispatch = useAppDispatch(); const modalContentRef = useRef(null); - const componentId = useId(); const handleCloseClick = () => { setIsClosing(true); From e99f74f55361f659befe09e32b7cee3a9e5b5583 Mon Sep 17 00:00:00 2001 From: Fernando Zanutto Date: Tue, 23 Apr 2024 19:35:40 -0300 Subject: [PATCH 045/140] trigger pipeline --- src/renderer/components/modal/modal.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/renderer/components/modal/modal.tsx b/src/renderer/components/modal/modal.tsx index 288930e3..33e07680 100644 --- a/src/renderer/components/modal/modal.tsx +++ b/src/renderer/components/modal/modal.tsx @@ -33,6 +33,7 @@ export function Modal({ if (time - zero <= 400) { requestAnimationFrame(animateClosing); } else { + onClose(); setIsClosing(false); } From d11c142032194ed87a220fedb7ebc4a039cc93fa Mon Sep 17 00:00:00 2001 From: Fernando Zanutto Date: Tue, 23 Apr 2024 19:35:40 -0300 Subject: [PATCH 046/140] trigger pipeline --- src/renderer/components/modal/modal.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/renderer/components/modal/modal.tsx b/src/renderer/components/modal/modal.tsx index 288930e3..33e07680 100644 --- a/src/renderer/components/modal/modal.tsx +++ b/src/renderer/components/modal/modal.tsx @@ -33,6 +33,7 @@ export function Modal({ if (time - zero <= 400) { requestAnimationFrame(animateClosing); } else { + onClose(); setIsClosing(false); } From 11f2b9902720fc15ba80c54d4833b993ddc63316 Mon Sep 17 00:00:00 2001 From: Fernando Zanutto Date: Tue, 23 Apr 2024 19:35:48 -0300 Subject: [PATCH 047/140] trigger pipeline --- src/renderer/components/modal/modal.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/renderer/components/modal/modal.tsx b/src/renderer/components/modal/modal.tsx index 33e07680..288930e3 100644 --- a/src/renderer/components/modal/modal.tsx +++ b/src/renderer/components/modal/modal.tsx @@ -33,7 +33,6 @@ export function Modal({ if (time - zero <= 400) { requestAnimationFrame(animateClosing); } else { - onClose(); setIsClosing(false); } From 6131c1406793414364e1502e073facdc1715a924 Mon Sep 17 00:00:00 2001 From: Fernando Zanutto Date: Tue, 23 Apr 2024 19:35:48 -0300 Subject: [PATCH 048/140] trigger pipeline --- src/renderer/components/modal/modal.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/renderer/components/modal/modal.tsx b/src/renderer/components/modal/modal.tsx index 33e07680..288930e3 100644 --- a/src/renderer/components/modal/modal.tsx +++ b/src/renderer/components/modal/modal.tsx @@ -33,7 +33,6 @@ export function Modal({ if (time - zero <= 400) { requestAnimationFrame(animateClosing); } else { - onClose(); setIsClosing(false); } From cc02bedd65a9ce859dc0cbf33209e55be91681fc Mon Sep 17 00:00:00 2001 From: Fernando Zanutto Date: Tue, 23 Apr 2024 19:44:01 -0300 Subject: [PATCH 049/140] lint warnings --- src/renderer/components/modal/modal.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/renderer/components/modal/modal.tsx b/src/renderer/components/modal/modal.tsx index 288930e3..9b5f8cf5 100644 --- a/src/renderer/components/modal/modal.tsx +++ b/src/renderer/components/modal/modal.tsx @@ -1,4 +1,4 @@ -import { useEffect, useRef, useState } from "react"; +import { useCallback, useEffect, useRef, useState } from "react"; import { createPortal } from "react-dom"; import { XIcon } from "@primer/octicons-react"; @@ -25,7 +25,7 @@ export function Modal({ const dispatch = useAppDispatch(); const modalContentRef = useRef(null); - const handleCloseClick = () => { + const handleCloseClick = useCallback(() => { setIsClosing(true); const zero = performance.now(); @@ -37,7 +37,7 @@ export function Modal({ setIsClosing(false); } }); - }; + }, [onClose]); const isTopMostModal = () => { const openModals = document.querySelectorAll("[role=modal]"); From b60c319dfd675ec7ebfcde468e94ebd217e3b362 Mon Sep 17 00:00:00 2001 From: Fernando Zanutto Date: Tue, 23 Apr 2024 19:44:01 -0300 Subject: [PATCH 050/140] lint warnings --- src/renderer/components/modal/modal.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/renderer/components/modal/modal.tsx b/src/renderer/components/modal/modal.tsx index 288930e3..9b5f8cf5 100644 --- a/src/renderer/components/modal/modal.tsx +++ b/src/renderer/components/modal/modal.tsx @@ -1,4 +1,4 @@ -import { useEffect, useRef, useState } from "react"; +import { useCallback, useEffect, useRef, useState } from "react"; import { createPortal } from "react-dom"; import { XIcon } from "@primer/octicons-react"; @@ -25,7 +25,7 @@ export function Modal({ const dispatch = useAppDispatch(); const modalContentRef = useRef(null); - const handleCloseClick = () => { + const handleCloseClick = useCallback(() => { setIsClosing(true); const zero = performance.now(); @@ -37,7 +37,7 @@ export function Modal({ setIsClosing(false); } }); - }; + }, [onClose]); const isTopMostModal = () => { const openModals = document.querySelectorAll("[role=modal]"); From 76bd345c4759570df74b4dab4bbc597c0ba10a60 Mon Sep 17 00:00:00 2001 From: Magrid Date: Wed, 24 Apr 2024 20:21:37 +0200 Subject: [PATCH 051/140] fix french translation --- src/locales/fr/translation.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/locales/fr/translation.json b/src/locales/fr/translation.json index e3d2bd3d..154186be 100644 --- a/src/locales/fr/translation.json +++ b/src/locales/fr/translation.json @@ -25,7 +25,7 @@ "downloads": "Téléchargements", "search_results": "Résultats de la recherche", "settings": "Paramètres", - "home": "Maison" + "home": "Accueil" }, "bottom_panel": { "no_downloads_in_progress": "Aucun téléchargement en cours", From e18200d79628da6009fb83108050c46bd4dd637e Mon Sep 17 00:00:00 2001 From: Magrid Date: Wed, 24 Apr 2024 20:21:37 +0200 Subject: [PATCH 052/140] fix french translation --- src/locales/fr/translation.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/locales/fr/translation.json b/src/locales/fr/translation.json index e3d2bd3d..154186be 100644 --- a/src/locales/fr/translation.json +++ b/src/locales/fr/translation.json @@ -25,7 +25,7 @@ "downloads": "Téléchargements", "search_results": "Résultats de la recherche", "settings": "Paramètres", - "home": "Maison" + "home": "Accueil" }, "bottom_panel": { "no_downloads_in_progress": "Aucun téléchargement en cours", From b833e7e351beb2d0db2fe38917814c7853b9b057 Mon Sep 17 00:00:00 2001 From: Hydra Date: Thu, 25 Apr 2024 05:57:01 +0100 Subject: [PATCH 053/140] chore: merge with main --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c06126d3..d168333d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -52,7 +52,7 @@ jobs: with: vt_api_key: ${{ secrets.VT_API_KEY }} files: | - .exe$ + ./hydra-download-manager/hydra-download-manager.exe # - name: Publish # run: yarn run publish From c07f82ce4977c9c006e85d1cf07ee4cf26832301 Mon Sep 17 00:00:00 2001 From: Hydra Date: Thu, 25 Apr 2024 05:57:01 +0100 Subject: [PATCH 054/140] chore: merge with main --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c06126d3..d168333d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -52,7 +52,7 @@ jobs: with: vt_api_key: ${{ secrets.VT_API_KEY }} files: | - .exe$ + ./hydra-download-manager/hydra-download-manager.exe # - name: Publish # run: yarn run publish From 4b57ea48e8f557e60dd50138f3e59a8ec1482f29 Mon Sep 17 00:00:00 2001 From: Hydra Date: Thu, 25 Apr 2024 20:54:38 +0100 Subject: [PATCH 055/140] fix: fixing typechecks --- .eslintrc.cjs | 13 + .github/workflows/build.yml | 21 +- package.json | 6 +- src/main/events/catalogue/get-games.ts | 2 +- src/main/events/catalogue/get-random-game.ts | 2 +- src/main/events/index.ts | 1 - src/main/events/library/remove-game.ts | 16 +- .../events/torrenting/cancel-game-download.ts | 2 +- .../events/torrenting/pause-game-download.ts | 2 +- .../torrenting/remove-game-from-download.ts | 34 --- .../user-preferences/get-user-preferences.ts | 2 +- src/main/main.ts | 8 +- .../services/repack-tracker/cpg-repacks.ts | 8 +- src/main/services/repack-tracker/index.ts | 2 +- .../services/repack-tracker/online-fix.ts | 8 +- src/main/services/steam-250.ts | 11 +- src/main/services/window-manager.ts | 21 +- src/renderer/src/app.tsx | 2 +- .../components/async-image/async-image.tsx | 2 + .../components/bottom-panel/bottom-panel.tsx | 2 +- yarn.lock | 236 +++++++++++++++++- 21 files changed, 311 insertions(+), 90 deletions(-) delete mode 100644 src/main/events/torrenting/remove-game-from-download.ts diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 9d21efd0..49aa25e2 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -3,7 +3,20 @@ module.exports = { "eslint:recommended", "plugin:react/recommended", "plugin:react/jsx-runtime", + "plugin:react-hooks/recommended", "@electron-toolkit/eslint-config-ts/recommended", "prettier", ], + rules: { + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/no-unused-vars": [ + "error", + { + argsIgnorePattern: "^_", + varsIgnorePattern: "^_", + caughtErrorsIgnorePattern: "^_", + }, + ], + "@typescript-eslint/no-explicit-any": "warn", + }, }; diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d168333d..973f95bc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -47,6 +47,17 @@ jobs: - name: Build with cx_Freeze run: python torrent-client/setup.py build + - name: Publish + run: yarn run publish + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + MAIN_VITE_STEAMGRIDDB_API_KEY: ${{ secrets.STEAMGRIDDB_API_KEY }} + SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} + MAIN_VITE_SENTRY_DSN: ${{ vars.SENTRY_DSN }} + RENDERER_VITE_SENTRY_DSN: ${{ vars.SENTRY_DSN }} + MAIN_VITE_ONLINEFIX_USERNAME: ${{ secrets.ONLINEFIX_USERNAME }} + MAIN_VITE_ONLINEFIX_PASSWORD: ${{ secrets.ONLINEFIX_PASSWORD }} + - name: VirusTotal Scan uses: crazy-max/ghaction-virustotal@v4 with: @@ -54,16 +65,6 @@ jobs: files: | ./hydra-download-manager/hydra-download-manager.exe - # - name: Publish - # run: yarn run publish - # env: - # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # STEAMGRIDDB_API_KEY: ${{ secrets.STEAMGRIDDB_API_KEY }} - # SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} - # SENTRY_DSN: ${{ vars.SENTRY_DSN }} - # ONLINEFIX_USERNAME: ${{ secrets.ONLINEFIX_USERNAME }} - # ONLINEFIX_PASSWORD: ${{ secrets.ONLINEFIX_PASSWORD }} - - name: Create artifact uses: actions/upload-artifact@v4 with: diff --git a/package.json b/package.json index 07e3e883..60f05f45 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "hydra", "version": "1.0.0", - "description": "An Electron application with React and TypeScript", + "description": "Hydra", "main": "./out/main/index.js", "author": "Los Broxas", "homepage": "https://electron-vite.org", @@ -43,6 +43,7 @@ "color.js": "^1.2.0", "date-fns": "^3.6.0", "flexsearch": "^0.7.43", + "got-scraping": "^4.0.5", "i18next": "^23.11.2", "i18next-browser-languagedetector": "^7.2.1", "jsdom": "^24.0.0", @@ -56,6 +57,7 @@ "react-router-dom": "^6.22.3", "tasklist": "^5.0.0", "typeorm": "^0.3.20", + "windows-1251": "^3.0.4", "winston": "^3.13.0", "yaml": "^2.4.1" }, @@ -64,6 +66,7 @@ "@electron-toolkit/eslint-config-ts": "^1.0.1", "@electron-toolkit/tsconfig": "^1.0.1", "@swc/core": "^1.4.16", + "@types/jsdom": "^21.1.6", "@types/lodash-es": "^4.17.12", "@types/node": "^20.12.7", "@types/react": "^18.2.48", @@ -75,6 +78,7 @@ "electron-vite": "^2.0.0", "eslint": "^8.56.0", "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react-hooks": "^4.6.0", "prettier": "^3.2.4", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/src/main/events/catalogue/get-games.ts b/src/main/events/catalogue/get-games.ts index 64c491ae..b2766928 100644 --- a/src/main/events/catalogue/get-games.ts +++ b/src/main/events/catalogue/get-games.ts @@ -9,7 +9,7 @@ const steamGames = stateManager.getValue("steamGames"); const getGames = async ( _event: Electron.IpcMainInvokeEvent, - take?: number, + take = 12, cursor = 0 ): Promise<{ results: CatalogueEntry[]; cursor: number }> => { const results: CatalogueEntry[] = []; diff --git a/src/main/events/catalogue/get-random-game.ts b/src/main/events/catalogue/get-random-game.ts index 335fa026..a7483f0e 100644 --- a/src/main/events/catalogue/get-random-game.ts +++ b/src/main/events/catalogue/get-random-game.ts @@ -6,7 +6,7 @@ import { registerEvent } from "../register-event"; import { searchGames, searchRepacks } from "../helpers/search-games"; import { formatName } from "@main/helpers"; -const getRandomGame = async (_event: Electron.IpcMainInvokeEvent) => { +const getRandomGame = async () => { return getRandomSteam250List().then(async (games) => { const shuffledList = shuffle(games); diff --git a/src/main/events/index.ts b/src/main/events/index.ts index e62720fb..4ce550c6 100644 --- a/src/main/events/index.ts +++ b/src/main/events/index.ts @@ -25,7 +25,6 @@ import "./torrenting/cancel-game-download"; import "./torrenting/pause-game-download"; import "./torrenting/resume-game-download"; import "./torrenting/start-game-download"; -import "./torrenting/remove-game-from-download"; import "./user-preferences/get-user-preferences"; import "./user-preferences/update-user-preferences"; diff --git a/src/main/events/library/remove-game.ts b/src/main/events/library/remove-game.ts index 64e84b7d..d571e821 100644 --- a/src/main/events/library/remove-game.ts +++ b/src/main/events/library/remove-game.ts @@ -1,10 +1,24 @@ import { registerEvent } from "../register-event"; import { gameRepository } from "../../repository"; +import { GameStatus } from "@main/constants"; const removeGame = async ( _event: Electron.IpcMainInvokeEvent, gameId: number -) => gameRepository.delete({ id: gameId }); +) => { + await gameRepository.update( + { + id: gameId, + status: GameStatus.Cancelled, + }, + { + status: null, + downloadPath: null, + bytesDownloaded: 0, + progress: 0, + } + ); +}; registerEvent(removeGame, { name: "removeGame", diff --git a/src/main/events/torrenting/cancel-game-download.ts b/src/main/events/torrenting/cancel-game-download.ts index a1a2e6b7..77e633b0 100644 --- a/src/main/events/torrenting/cancel-game-download.ts +++ b/src/main/events/torrenting/cancel-game-download.ts @@ -42,7 +42,7 @@ const cancelGameDownload = async ( game.status !== GameStatus.Seeding ) { writePipe.write({ action: "cancel" }); - if (result.affected) WindowManager.mainWindow.setProgressBar(-1); + if (result.affected) WindowManager.mainWindow?.setProgressBar(-1); } }); }; diff --git a/src/main/events/torrenting/pause-game-download.ts b/src/main/events/torrenting/pause-game-download.ts index d89f2f72..943bea37 100644 --- a/src/main/events/torrenting/pause-game-download.ts +++ b/src/main/events/torrenting/pause-game-download.ts @@ -24,7 +24,7 @@ const pauseGameDownload = async ( .then((result) => { if (result.affected) { writePipe.write({ action: "pause" }); - WindowManager.mainWindow.setProgressBar(-1); + WindowManager.mainWindow?.setProgressBar(-1); } }); }; diff --git a/src/main/events/torrenting/remove-game-from-download.ts b/src/main/events/torrenting/remove-game-from-download.ts deleted file mode 100644 index 47c1ebe6..00000000 --- a/src/main/events/torrenting/remove-game-from-download.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { GameStatus } from "@main/constants"; -import { gameRepository } from "@main/repository"; - -import { registerEvent } from "../register-event"; - -const removeGameFromDownload = async ( - _event: Electron.IpcMainInvokeEvent, - gameId: number -) => { - const game = await gameRepository.findOne({ - where: { - id: gameId, - status: GameStatus.Cancelled, - }, - }); - - if (!game) return; - - gameRepository.update( - { - id: game.id, - }, - { - status: null, - downloadPath: null, - bytesDownloaded: 0, - progress: 0, - } - ); -}; - -registerEvent(removeGameFromDownload, { - name: "removeGameFromDownload", -}); diff --git a/src/main/events/user-preferences/get-user-preferences.ts b/src/main/events/user-preferences/get-user-preferences.ts index 219713eb..03b4ae9d 100644 --- a/src/main/events/user-preferences/get-user-preferences.ts +++ b/src/main/events/user-preferences/get-user-preferences.ts @@ -1,7 +1,7 @@ import { userPreferencesRepository } from "@main/repository"; import { registerEvent } from "../register-event"; -const getUserPreferences = async (_event: Electron.IpcMainInvokeEvent) => +const getUserPreferences = async () => userPreferencesRepository.findOne({ where: { id: 1 }, }); diff --git a/src/main/main.ts b/src/main/main.ts index a98b804c..c54a7e9a 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -5,7 +5,7 @@ import { getNewRepacksFromCPG, getNewRepacksFromUser, // getNewRepacksFromXatab, - // getNewRepacksFromOnlineFix, + getNewRepacksFromOnlineFix, readPipe, startProcessWatcher, writePipe, @@ -79,9 +79,9 @@ const checkForNewRepacks = async () => { getNewRepacksFromCPG( existingRepacks.filter((repack) => repack.repacker === "CPG") ), - // getNewRepacksFromOnlineFix( - // existingRepacks.filter((repack) => repack.repacker === "onlinefix") - // ), + getNewRepacksFromOnlineFix( + existingRepacks.filter((repack) => repack.repacker === "onlinefix") + ), track1337xUsers(existingRepacks), ]).then(() => { repackRepository.count().then((count) => { diff --git a/src/main/services/repack-tracker/cpg-repacks.ts b/src/main/services/repack-tracker/cpg-repacks.ts index 0d7c172b..c4b62c1f 100644 --- a/src/main/services/repack-tracker/cpg-repacks.ts +++ b/src/main/services/repack-tracker/cpg-repacks.ts @@ -19,17 +19,17 @@ export const getNewRepacksFromCPG = async ( try { Array.from(window.document.querySelectorAll(".post")).forEach(($post) => { const $title = $post.querySelector(".entry-title"); - const uploadDate = $post.querySelector("time").getAttribute("datetime"); + const uploadDate = $post.querySelector("time")?.getAttribute("datetime"); const $downloadInfo = Array.from( $post.querySelectorAll(".wp-block-heading") - ).find(($heading) => $heading.textContent.startsWith("Download")); + ).find(($heading) => $heading.textContent?.startsWith("Download")); /* Side note: CPG often misspells "Magnet" as "Magent" */ const $magnet = Array.from($post.querySelectorAll("a")).find( ($a) => - $a.textContent.startsWith("Magnet") || - $a.textContent.startsWith("Magent") + $a.textContent?.startsWith("Magnet") || + $a.textContent?.startsWith("Magent") ); const fileSize = $downloadInfo.textContent diff --git a/src/main/services/repack-tracker/index.ts b/src/main/services/repack-tracker/index.ts index fb345fae..7bd3ce31 100644 --- a/src/main/services/repack-tracker/index.ts +++ b/src/main/services/repack-tracker/index.ts @@ -2,4 +2,4 @@ export * from "./1337x"; export * from "./xatab"; export * from "./cpg-repacks"; export * from "./gog"; -// export * from "./online-fix"; +export * from "./online-fix"; diff --git a/src/main/services/repack-tracker/online-fix.ts b/src/main/services/repack-tracker/online-fix.ts index c572629c..2a69dd70 100644 --- a/src/main/services/repack-tracker/online-fix.ts +++ b/src/main/services/repack-tracker/online-fix.ts @@ -88,7 +88,7 @@ export const getNewRepacksFromOnlineFix = async ( const repacks: GameRepackInput[] = []; const articles = Array.from(document.querySelectorAll(".news")); const totalPages = Number( - document.querySelector("nav > a:nth-child(13)").textContent + document.querySelector("nav > a:nth-child(13)")?.textContent ); try { @@ -186,8 +186,10 @@ export const getNewRepacksFromOnlineFix = async ( }); }) ); - } catch (err) { - logger.error(err.message, { method: "getNewRepacksFromOnlineFix" }); + } catch (err: unknown) { + logger.error((err as Error).message, { + method: "getNewRepacksFromOnlineFix", + }); } const newRepacks = repacks.filter( diff --git a/src/main/services/steam-250.ts b/src/main/services/steam-250.ts index 32ccdc56..bec2c604 100644 --- a/src/main/services/steam-250.ts +++ b/src/main/services/steam-250.ts @@ -7,17 +7,16 @@ export const requestSteam250 = async (path: string) => { const { window } = new JSDOM(response.data); const { document } = window; - return Array.from(document.querySelectorAll(".appline .title a")).map( - ($title: HTMLAnchorElement) => { - const steamGameUrl = $title.href; - if (!steamGameUrl) return null; + return Array.from(document.querySelectorAll(".appline .title a")) + .filter(($title) => Boolean(($title as HTMLAnchorElement).href)) + .map(($title) => { + const steamGameUrl = ($title as HTMLAnchorElement).href; return { title: $title.textContent, objectID: steamGameUrl.split("/").pop(), }; - } - ); + }); }); }; diff --git a/src/main/services/window-manager.ts b/src/main/services/window-manager.ts index 0eea8e96..766eb826 100644 --- a/src/main/services/window-manager.ts +++ b/src/main/services/window-manager.ts @@ -12,13 +12,16 @@ export class WindowManager { // HMR for renderer base on electron-vite cli. // Load the remote URL for development or the local html file for production. if (is.dev && process.env["ELECTRON_RENDERER_URL"]) { - this.mainWindow.loadURL( + this.mainWindow?.loadURL( `${process.env["ELECTRON_RENDERER_URL"]}#/${hash}` ); } else { - this.mainWindow.loadFile(path.join(__dirname, "../renderer/index.html"), { - hash, - }); + this.mainWindow?.loadFile( + path.join(__dirname, "../renderer/index.html"), + { + hash, + } + ); } } @@ -47,7 +50,7 @@ export class WindowManager { this.mainWindow.removeMenu(); this.mainWindow.on("close", () => { - WindowManager.mainWindow.setProgressBar(-1); + WindowManager.mainWindow?.setProgressBar(-1); }); } @@ -55,8 +58,8 @@ export class WindowManager { if (!this.mainWindow) this.createMainWindow(); this.loadURL(hash); - if (this.mainWindow.isMinimized()) this.mainWindow.restore(); - this.mainWindow.focus(); + if (this.mainWindow?.isMinimized()) this.mainWindow.restore(); + this.mainWindow?.focus(); } public static createSystemTray(language: string) { @@ -93,10 +96,10 @@ export class WindowManager { if (process.platform === "win32") { tray.addListener("click", () => { if (this.mainWindow) { - if (WindowManager.mainWindow.isMinimized()) + if (WindowManager.mainWindow?.isMinimized()) WindowManager.mainWindow.restore(); - WindowManager.mainWindow.focus(); + WindowManager.mainWindow?.focus(); return; } diff --git a/src/renderer/src/app.tsx b/src/renderer/src/app.tsx index dd3488cc..6461c0d0 100644 --- a/src/renderer/src/app.tsx +++ b/src/renderer/src/app.tsx @@ -12,7 +12,7 @@ import { import * as styles from "./app.css"; import { themeClass } from "./theme.css"; -import { Outlet, useLocation, useNavigate } from "react-router-dom"; +import { useLocation, useNavigate } from "react-router-dom"; import { setSearch, clearSearch, diff --git a/src/renderer/src/components/async-image/async-image.tsx b/src/renderer/src/components/async-image/async-image.tsx index 857a9942..e3c0ee45 100644 --- a/src/renderer/src/components/async-image/async-image.tsx +++ b/src/renderer/src/components/async-image/async-image.tsx @@ -25,3 +25,5 @@ export const AsyncImage = forwardRef( return ; } ); + +AsyncImage.displayName = "AsyncImage"; diff --git a/src/renderer/src/components/bottom-panel/bottom-panel.tsx b/src/renderer/src/components/bottom-panel/bottom-panel.tsx index df1f49cb..ed9a54ed 100644 --- a/src/renderer/src/components/bottom-panel/bottom-panel.tsx +++ b/src/renderer/src/components/bottom-panel/bottom-panel.tsx @@ -61,7 +61,7 @@ export function BottomPanel() { - v{version} "{VERSION_CODENAME}" + v{version} "{VERSION_CODENAME}" ); diff --git a/yarn.lock b/yarn.lock index 6bf63b34..e708f28d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1024,11 +1024,16 @@ dependencies: "@sentry/types" "7.111.0" -"@sindresorhus/is@^4.0.0": +"@sindresorhus/is@^4.0.0", "@sindresorhus/is@^4.2.0": version "4.6.0" resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz" integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw== +"@sindresorhus/is@^5.2.0", "@sindresorhus/is@^5.3.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-5.6.0.tgz#41dd6093d34652cddb5d5bdeee04eafc33826668" + integrity sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g== + "@sqltools/formatter@^1.2.5": version "1.2.5" resolved "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.5.tgz" @@ -1205,6 +1210,13 @@ dependencies: defer-to-connect "^2.0.0" +"@szmarczak/http-timer@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-5.0.1.tgz#c7c1bf1141cdd4751b0399c8fc7b8b664cd5be3a" + integrity sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw== + dependencies: + defer-to-connect "^2.0.1" + "@thaunknown/thirty-two@^1.0.3": version "1.0.3" resolved "https://registry.npmjs.org/@thaunknown/thirty-two/-/thirty-two-1.0.3.tgz" @@ -1279,11 +1291,20 @@ dependencies: "@types/node" "*" -"@types/http-cache-semantics@*": +"@types/http-cache-semantics@*", "@types/http-cache-semantics@^4.0.2": version "4.0.4" resolved "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz" integrity sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA== +"@types/jsdom@^21.1.6": + version "21.1.6" + resolved "https://registry.yarnpkg.com/@types/jsdom/-/jsdom-21.1.6.tgz#bcbc7b245787ea863f3da1ef19aa1dcfb9271a1b" + integrity sha512-/7kkMsC+/kMs7gAYmmBR9P0vGTnOoLhQhyhQJSlXGI5bzTHp6xdo0TtKWQAsz6pmSAeVqKSbqeyP6hytqr9FDw== + dependencies: + "@types/node" "*" + "@types/tough-cookie" "*" + parse5 "^7.0.0" + "@types/json-schema@^7.0.12": version "7.0.15" resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz" @@ -1367,6 +1388,11 @@ resolved "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz" integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ== +"@types/tough-cookie@*": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.5.tgz#cb6e2a691b70cb177c6e3ae9c1d2e8b2ea8cd304" + integrity sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA== + "@types/triple-beam@^1.3.2": version "1.3.5" resolved "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz" @@ -1573,6 +1599,11 @@ acorn@^8.11.3, acorn@^8.9.0: resolved "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz" integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== +adm-zip@^0.5.9: + version "0.5.12" + resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.5.12.tgz#87786328e91d54b37358d8a50f954c4cd73ba60b" + integrity sha512-6TVU49mK6KZb4qG6xWaaM4C7sA/sgUMLy/JYMOzkcp3BvVLpW0fXDFQiIzAuxFCt/2+xD7fNIiPFAoLZPhVNLQ== + agent-base@6: version "6.0.2" resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz" @@ -1912,7 +1943,7 @@ braces@^3.0.2: dependencies: fill-range "^7.0.1" -browserslist@^4.22.2: +browserslist@^4.21.1, browserslist@^4.22.2: version "4.23.0" resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz" integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ== @@ -1993,6 +2024,24 @@ cacheable-lookup@^5.0.3: resolved "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz" integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA== +cacheable-lookup@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz#3476a8215d046e5a3202a9209dd13fec1f933a27" + integrity sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w== + +cacheable-request@^10.2.8: + version "10.2.14" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-10.2.14.tgz#eb915b665fda41b79652782df3f553449c406b9d" + integrity sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ== + dependencies: + "@types/http-cache-semantics" "^4.0.2" + get-stream "^6.0.1" + http-cache-semantics "^4.1.1" + keyv "^4.5.3" + mimic-response "^4.0.0" + normalize-url "^8.0.0" + responselike "^3.0.0" + cacheable-request@^7.0.2: version "7.0.4" resolved "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz" @@ -2017,11 +2066,16 @@ call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: get-intrinsic "^1.2.4" set-function-length "^1.2.1" -callsites@^3.0.0: +callsites@^3.0.0, callsites@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== +callsites@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-4.1.0.tgz#de72b98612eed4e1e2564c952498677faa9d86c2" + integrity sha512-aBMbD1Xxay75ViYezwT40aQONfr+pSXTHwNKvIXhXD6+LY3F1dLIcceoC5OZKBVHbXcysz1hL9D2w0JJIMXpUw== + camelcase@^6.2.0: version "6.3.0" resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" @@ -2392,7 +2446,7 @@ deepmerge@4.3.0, deepmerge@^4.2.2: resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.0.tgz" integrity sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og== -defer-to-connect@^2.0.0: +defer-to-connect@^2.0.0, defer-to-connect@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz" integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== @@ -2495,6 +2549,20 @@ dot-case@^3.0.4: no-case "^3.0.4" tslib "^2.0.3" +dot-prop@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-6.0.1.tgz#fc26b3cf142b9e59b74dbd39ed66ce620c681083" + integrity sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA== + dependencies: + is-obj "^2.0.0" + +dot-prop@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-7.2.0.tgz#468172a3529779814d21a779c1ba2f6d76609809" + integrity sha512-Ol/IPXUARn9CSbkrdV4VJo7uCy1I3VuSiWCaFSg+8BdUOzF9n3jefIpcgAydvUZbTdEBZs2vEiTiS9m61ssiDA== + dependencies: + type-fest "^2.11.2" + dotenv-expand@^5.1.0: version "5.1.0" resolved "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz" @@ -2829,6 +2897,11 @@ eslint-plugin-prettier@^5.0.1: prettier-linter-helpers "^1.0.0" synckit "^0.8.6" +eslint-plugin-react-hooks@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz#4c3e697ad95b77e93f8646aaa1630c1ba607edd3" + integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g== + eslint-plugin-react@^7.33.2: version "7.34.1" resolved "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz" @@ -3118,6 +3191,11 @@ foreground-child@^3.1.0: cross-spawn "^7.0.0" signal-exit "^4.0.1" +form-data-encoder@^2.1.2: + version "2.1.4" + resolved "https://registry.yarnpkg.com/form-data-encoder/-/form-data-encoder-2.1.4.tgz#261ea35d2a70d48d30ec7a9603130fa5515e9cd5" + integrity sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw== + form-data@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz" @@ -3204,6 +3282,14 @@ functions-have-names@^1.2.3: resolved "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== +generative-bayesian-network@^2.1.50: + version "2.1.50" + resolved "https://registry.yarnpkg.com/generative-bayesian-network/-/generative-bayesian-network-2.1.50.tgz#a576130befe0e30ccfebe5280fb2550649abadc9" + integrity sha512-iVmmQ4lpa41xqtrg6cbWuH1Qa2+C6tndb2dJmJazBEIQcnvz29ZYxbnqB1DAvbico3nGIVzF2Hvj2gZU9EewAQ== + dependencies: + adm-zip "^0.5.9" + tslib "^2.4.0" + gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" @@ -3237,6 +3323,11 @@ get-stream@^5.1.0: dependencies: pump "^3.0.0" +get-stream@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + get-symbol-description@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz" @@ -3338,6 +3429,19 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" +got-scraping@^4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/got-scraping/-/got-scraping-4.0.5.tgz#e1cab8ff2420d9c9f406bac405c10e8b324ec4ec" + integrity sha512-g+cMC5WOVOHd6S3JdTtm+zCwpWdd3jA1MYnkOwVF7MpbKP7EWv7ORUfXDcG3gTANJ1zYj9XffCrAjbH8ssHmfw== + dependencies: + got "^13.0.0" + header-generator "^2.1.41" + http2-wrapper "^2.2.0" + mimic-response "^4.0.0" + ow "^1.1.1" + quick-lru "^7.0.0" + tslib "^2.6.2" + got@^11.8.5: version "11.8.6" resolved "https://registry.npmjs.org/got/-/got-11.8.6.tgz" @@ -3355,6 +3459,23 @@ got@^11.8.5: p-cancelable "^2.0.0" responselike "^2.0.0" +got@^13.0.0: + version "13.0.0" + resolved "https://registry.yarnpkg.com/got/-/got-13.0.0.tgz#a2402862cef27a5d0d1b07c0fb25d12b58175422" + integrity sha512-XfBk1CxOOScDcMr9O1yKkNaQyy865NbYs+F7dr4H0LZMVgCj2Le59k6PqbNHoL5ToeaEQUYh6c6yMfVcc6SJxA== + dependencies: + "@sindresorhus/is" "^5.2.0" + "@szmarczak/http-timer" "^5.0.1" + cacheable-lookup "^7.0.0" + cacheable-request "^10.2.8" + decompress-response "^6.0.0" + form-data-encoder "^2.1.2" + get-stream "^6.0.1" + http2-wrapper "^2.1.10" + lowercase-keys "^3.0.0" + p-cancelable "^3.0.0" + responselike "^3.0.0" + graceful-fs@^4.1.6, graceful-fs@^4.2.0: version "4.2.11" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" @@ -3411,6 +3532,16 @@ hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: dependencies: function-bind "^1.1.2" +header-generator@^2.1.41: + version "2.1.50" + resolved "https://registry.yarnpkg.com/header-generator/-/header-generator-2.1.50.tgz#338fd7d92131dcaf71918b6ac8b9a26d6bb6acc0" + integrity sha512-Z37QBqcPzEqCCFQcOv1Kth1My3h4Vx+2V+aBipjrefZ2MFbVfYB/mo1v+OxiEJir5zSp9rX/z+BoqTuSAIGBLQ== + dependencies: + browserslist "^4.21.1" + generative-bayesian-network "^2.1.50" + ow "^0.28.1" + tslib "^2.4.0" + highlight.js@^10.7.1: version "10.7.3" resolved "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz" @@ -3444,7 +3575,7 @@ html-parse-stringify@^3.0.1: dependencies: void-elements "3.1.0" -http-cache-semantics@^4.0.0: +http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.1: version "4.1.1" resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz" integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== @@ -3474,6 +3605,14 @@ http2-wrapper@^1.0.0-beta.5.2: quick-lru "^5.1.1" resolve-alpn "^1.0.0" +http2-wrapper@^2.1.10, http2-wrapper@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-2.2.1.tgz#310968153dcdedb160d8b72114363ef5fce1f64a" + integrity sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ== + dependencies: + quick-lru "^5.1.1" + resolve-alpn "^1.2.0" + https-proxy-agent@^5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz" @@ -3700,6 +3839,11 @@ is-number@^7.0.0: resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== +is-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" + integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== + is-path-inside@^3.0.3: version "3.0.3" resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz" @@ -3973,6 +4117,11 @@ lodash-es@^4.17.21: resolved "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz" integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== +lodash.isequal@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== + lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz" @@ -4026,6 +4175,11 @@ lowercase-keys@^2.0.0: resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz" integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== +lowercase-keys@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-3.0.0.tgz#c5e7d442e37ead247ae9db117a9d0a467c89d4f2" + integrity sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ== + lru-cache@^10.2.0: version "10.2.0" resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz" @@ -4115,6 +4269,11 @@ mimic-response@^3.1.0: resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz" integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== +mimic-response@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-4.0.0.tgz#35468b19e7c75d10f5165ea25e75a5ceea7cf70f" + integrity sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg== + minimatch@9.0.3, minimatch@^9.0.1: version "9.0.3" resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz" @@ -4274,6 +4433,11 @@ normalize-url@^6.0.1: resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz" integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== +normalize-url@^8.0.0: + version "8.0.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-8.0.1.tgz#9b7d96af9836577c58f5883e939365fa15623a4a" + integrity sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w== + nwsapi@^2.2.7: version "2.2.8" resolved "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.8.tgz" @@ -4372,11 +4536,38 @@ outdent@^0.8.0: resolved "https://registry.npmjs.org/outdent/-/outdent-0.8.0.tgz" integrity sha512-KiOAIsdpUTcAXuykya5fnVVT+/5uS0Q1mrkRHcF89tpieSmY33O/tmc54CqwA+bfhbtEfZUNLHaPUiB9X3jt1A== +ow@^0.28.1: + version "0.28.2" + resolved "https://registry.yarnpkg.com/ow/-/ow-0.28.2.tgz#782b28102124e665c49ec7725e2066a129acf6bf" + integrity sha512-dD4UpyBh/9m4X2NVjA+73/ZPBRF+uF4zIMFvvQsabMiEK8x41L3rQ8EENOi35kyyoaJwNxEeJcP6Fj1H4U409Q== + dependencies: + "@sindresorhus/is" "^4.2.0" + callsites "^3.1.0" + dot-prop "^6.0.1" + lodash.isequal "^4.5.0" + vali-date "^1.0.0" + +ow@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ow/-/ow-1.1.1.tgz#354a0f7df9d8d0cf961b29116daf972ef6be1632" + integrity sha512-sJBRCbS5vh1Jp9EOgwp1Ws3c16lJrUkJYlvWTYC03oyiYVwS/ns7lKRWow4w4XjDyTrA2pplQv4B2naWSR6yDA== + dependencies: + "@sindresorhus/is" "^5.3.0" + callsites "^4.0.0" + dot-prop "^7.2.0" + lodash.isequal "^4.5.0" + vali-date "^1.0.0" + p-cancelable@^2.0.0: version "2.1.1" resolved "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz" integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg== +p-cancelable@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-3.0.0.tgz#63826694b54d61ca1c20ebcb6d3ecf5e14cd8050" + integrity sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw== + p-limit@^3.0.2: version "3.1.0" resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" @@ -4437,7 +4628,7 @@ parse5@^6.0.1: resolved "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz" integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== -parse5@^7.1.2: +parse5@^7.0.0, parse5@^7.1.2: version "7.1.2" resolved "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz" integrity sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw== @@ -4629,6 +4820,11 @@ quick-lru@^5.1.1: resolved "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz" integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== +quick-lru@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-7.0.0.tgz#447f6925b33ae4d2d637e211967d74bae4b99c3f" + integrity sha512-MX8gB7cVYTrYcFfAnfLlhRd0+Toyl8yX8uBx1MrX7K0jegiz9TumwOK27ldXrgDlHRdVi+MqU9Ssw6dr4BNreg== + rc@^1.2.7: version "1.2.8" resolved "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz" @@ -4784,7 +4980,7 @@ reselect@^5.0.1: resolved "https://registry.npmjs.org/reselect/-/reselect-5.1.0.tgz" integrity sha512-aw7jcGLDpSgNDyWBQLv2cedml85qd95/iszJjN988zX1t7AVRJi19d9kto5+W7oCfQ94gyo40dVbT6g2k4/kXg== -resolve-alpn@^1.0.0: +resolve-alpn@^1.0.0, resolve-alpn@^1.2.0: version "1.2.1" resolved "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz" integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g== @@ -4810,6 +5006,13 @@ responselike@^2.0.0: dependencies: lowercase-keys "^2.0.0" +responselike@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-3.0.0.tgz#20decb6c298aff0dbee1c355ca95461d42823626" + integrity sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg== + dependencies: + lowercase-keys "^3.0.0" + retry@^0.12.0: version "0.12.0" resolved "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz" @@ -5403,7 +5606,7 @@ ts-api-utils@^1.0.1: resolved "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz" integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== -tslib@^2.0.3, tslib@^2.5.0, tslib@^2.6.2: +tslib@^2.0.3, tslib@^2.4.0, tslib@^2.5.0, tslib@^2.6.2: version "2.6.2" resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz" integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== @@ -5432,6 +5635,11 @@ type-fest@^0.20.2: resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== +type-fest@^2.11.2: + version "2.19.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" + integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== + typed-array-buffer@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz" @@ -5587,6 +5795,11 @@ uuid@^9.0.0: resolved "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz" integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== +vali-date@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/vali-date/-/vali-date-1.0.0.tgz#1b904a59609fb328ef078138420934f6b86709a6" + integrity sha512-sgECfZthyaCKW10N0fm27cg8HYTFK5qMWgypqkXMQ4Wbl/zZKx7xZICgcoxIIE+WFAP/MBL2EFwC/YvLxw3Zeg== + verror@^1.10.0: version "1.10.1" resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.1.tgz#4bf09eeccf4563b109ed4b3d458380c972b0cdeb" @@ -5726,6 +5939,11 @@ which@^2.0.1: dependencies: isexe "^2.0.0" +windows-1251@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/windows-1251/-/windows-1251-3.0.4.tgz#984b9f2e76befd9ec2e825f9fe77b681fadcdb55" + integrity sha512-H6W68MVertlR74xVuwa2pdQ1jR5qksk+oZX6QXFhL5OYj/ZZxViob8UyGLfXPwsCijuaV7NUYOYkK0oXSaWW5g== + winston-transport@^4.7.0: version "4.7.0" resolved "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.0.tgz" From f9223ad36d0e7902a1e4aa33a2c9295bf36cb61a Mon Sep 17 00:00:00 2001 From: Hydra Date: Thu, 25 Apr 2024 20:54:38 +0100 Subject: [PATCH 056/140] fix: fixing typechecks --- .eslintrc.cjs | 13 + .github/workflows/build.yml | 21 +- package.json | 6 +- src/main/events/catalogue/get-games.ts | 2 +- src/main/events/catalogue/get-random-game.ts | 2 +- src/main/events/index.ts | 1 - src/main/events/library/remove-game.ts | 16 +- .../events/torrenting/cancel-game-download.ts | 2 +- .../events/torrenting/pause-game-download.ts | 2 +- .../torrenting/remove-game-from-download.ts | 34 --- .../user-preferences/get-user-preferences.ts | 2 +- src/main/main.ts | 8 +- .../services/repack-tracker/cpg-repacks.ts | 8 +- src/main/services/repack-tracker/index.ts | 2 +- .../services/repack-tracker/online-fix.ts | 8 +- src/main/services/steam-250.ts | 11 +- src/main/services/window-manager.ts | 21 +- src/renderer/src/app.tsx | 2 +- .../components/async-image/async-image.tsx | 2 + .../components/bottom-panel/bottom-panel.tsx | 2 +- yarn.lock | 236 +++++++++++++++++- 21 files changed, 311 insertions(+), 90 deletions(-) delete mode 100644 src/main/events/torrenting/remove-game-from-download.ts diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 9d21efd0..49aa25e2 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -3,7 +3,20 @@ module.exports = { "eslint:recommended", "plugin:react/recommended", "plugin:react/jsx-runtime", + "plugin:react-hooks/recommended", "@electron-toolkit/eslint-config-ts/recommended", "prettier", ], + rules: { + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/no-unused-vars": [ + "error", + { + argsIgnorePattern: "^_", + varsIgnorePattern: "^_", + caughtErrorsIgnorePattern: "^_", + }, + ], + "@typescript-eslint/no-explicit-any": "warn", + }, }; diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d168333d..973f95bc 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -47,6 +47,17 @@ jobs: - name: Build with cx_Freeze run: python torrent-client/setup.py build + - name: Publish + run: yarn run publish + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + MAIN_VITE_STEAMGRIDDB_API_KEY: ${{ secrets.STEAMGRIDDB_API_KEY }} + SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} + MAIN_VITE_SENTRY_DSN: ${{ vars.SENTRY_DSN }} + RENDERER_VITE_SENTRY_DSN: ${{ vars.SENTRY_DSN }} + MAIN_VITE_ONLINEFIX_USERNAME: ${{ secrets.ONLINEFIX_USERNAME }} + MAIN_VITE_ONLINEFIX_PASSWORD: ${{ secrets.ONLINEFIX_PASSWORD }} + - name: VirusTotal Scan uses: crazy-max/ghaction-virustotal@v4 with: @@ -54,16 +65,6 @@ jobs: files: | ./hydra-download-manager/hydra-download-manager.exe - # - name: Publish - # run: yarn run publish - # env: - # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - # STEAMGRIDDB_API_KEY: ${{ secrets.STEAMGRIDDB_API_KEY }} - # SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} - # SENTRY_DSN: ${{ vars.SENTRY_DSN }} - # ONLINEFIX_USERNAME: ${{ secrets.ONLINEFIX_USERNAME }} - # ONLINEFIX_PASSWORD: ${{ secrets.ONLINEFIX_PASSWORD }} - - name: Create artifact uses: actions/upload-artifact@v4 with: diff --git a/package.json b/package.json index 07e3e883..60f05f45 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "hydra", "version": "1.0.0", - "description": "An Electron application with React and TypeScript", + "description": "Hydra", "main": "./out/main/index.js", "author": "Los Broxas", "homepage": "https://electron-vite.org", @@ -43,6 +43,7 @@ "color.js": "^1.2.0", "date-fns": "^3.6.0", "flexsearch": "^0.7.43", + "got-scraping": "^4.0.5", "i18next": "^23.11.2", "i18next-browser-languagedetector": "^7.2.1", "jsdom": "^24.0.0", @@ -56,6 +57,7 @@ "react-router-dom": "^6.22.3", "tasklist": "^5.0.0", "typeorm": "^0.3.20", + "windows-1251": "^3.0.4", "winston": "^3.13.0", "yaml": "^2.4.1" }, @@ -64,6 +66,7 @@ "@electron-toolkit/eslint-config-ts": "^1.0.1", "@electron-toolkit/tsconfig": "^1.0.1", "@swc/core": "^1.4.16", + "@types/jsdom": "^21.1.6", "@types/lodash-es": "^4.17.12", "@types/node": "^20.12.7", "@types/react": "^18.2.48", @@ -75,6 +78,7 @@ "electron-vite": "^2.0.0", "eslint": "^8.56.0", "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react-hooks": "^4.6.0", "prettier": "^3.2.4", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/src/main/events/catalogue/get-games.ts b/src/main/events/catalogue/get-games.ts index 64c491ae..b2766928 100644 --- a/src/main/events/catalogue/get-games.ts +++ b/src/main/events/catalogue/get-games.ts @@ -9,7 +9,7 @@ const steamGames = stateManager.getValue("steamGames"); const getGames = async ( _event: Electron.IpcMainInvokeEvent, - take?: number, + take = 12, cursor = 0 ): Promise<{ results: CatalogueEntry[]; cursor: number }> => { const results: CatalogueEntry[] = []; diff --git a/src/main/events/catalogue/get-random-game.ts b/src/main/events/catalogue/get-random-game.ts index 335fa026..a7483f0e 100644 --- a/src/main/events/catalogue/get-random-game.ts +++ b/src/main/events/catalogue/get-random-game.ts @@ -6,7 +6,7 @@ import { registerEvent } from "../register-event"; import { searchGames, searchRepacks } from "../helpers/search-games"; import { formatName } from "@main/helpers"; -const getRandomGame = async (_event: Electron.IpcMainInvokeEvent) => { +const getRandomGame = async () => { return getRandomSteam250List().then(async (games) => { const shuffledList = shuffle(games); diff --git a/src/main/events/index.ts b/src/main/events/index.ts index e62720fb..4ce550c6 100644 --- a/src/main/events/index.ts +++ b/src/main/events/index.ts @@ -25,7 +25,6 @@ import "./torrenting/cancel-game-download"; import "./torrenting/pause-game-download"; import "./torrenting/resume-game-download"; import "./torrenting/start-game-download"; -import "./torrenting/remove-game-from-download"; import "./user-preferences/get-user-preferences"; import "./user-preferences/update-user-preferences"; diff --git a/src/main/events/library/remove-game.ts b/src/main/events/library/remove-game.ts index 64e84b7d..d571e821 100644 --- a/src/main/events/library/remove-game.ts +++ b/src/main/events/library/remove-game.ts @@ -1,10 +1,24 @@ import { registerEvent } from "../register-event"; import { gameRepository } from "../../repository"; +import { GameStatus } from "@main/constants"; const removeGame = async ( _event: Electron.IpcMainInvokeEvent, gameId: number -) => gameRepository.delete({ id: gameId }); +) => { + await gameRepository.update( + { + id: gameId, + status: GameStatus.Cancelled, + }, + { + status: null, + downloadPath: null, + bytesDownloaded: 0, + progress: 0, + } + ); +}; registerEvent(removeGame, { name: "removeGame", diff --git a/src/main/events/torrenting/cancel-game-download.ts b/src/main/events/torrenting/cancel-game-download.ts index a1a2e6b7..77e633b0 100644 --- a/src/main/events/torrenting/cancel-game-download.ts +++ b/src/main/events/torrenting/cancel-game-download.ts @@ -42,7 +42,7 @@ const cancelGameDownload = async ( game.status !== GameStatus.Seeding ) { writePipe.write({ action: "cancel" }); - if (result.affected) WindowManager.mainWindow.setProgressBar(-1); + if (result.affected) WindowManager.mainWindow?.setProgressBar(-1); } }); }; diff --git a/src/main/events/torrenting/pause-game-download.ts b/src/main/events/torrenting/pause-game-download.ts index d89f2f72..943bea37 100644 --- a/src/main/events/torrenting/pause-game-download.ts +++ b/src/main/events/torrenting/pause-game-download.ts @@ -24,7 +24,7 @@ const pauseGameDownload = async ( .then((result) => { if (result.affected) { writePipe.write({ action: "pause" }); - WindowManager.mainWindow.setProgressBar(-1); + WindowManager.mainWindow?.setProgressBar(-1); } }); }; diff --git a/src/main/events/torrenting/remove-game-from-download.ts b/src/main/events/torrenting/remove-game-from-download.ts deleted file mode 100644 index 47c1ebe6..00000000 --- a/src/main/events/torrenting/remove-game-from-download.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { GameStatus } from "@main/constants"; -import { gameRepository } from "@main/repository"; - -import { registerEvent } from "../register-event"; - -const removeGameFromDownload = async ( - _event: Electron.IpcMainInvokeEvent, - gameId: number -) => { - const game = await gameRepository.findOne({ - where: { - id: gameId, - status: GameStatus.Cancelled, - }, - }); - - if (!game) return; - - gameRepository.update( - { - id: game.id, - }, - { - status: null, - downloadPath: null, - bytesDownloaded: 0, - progress: 0, - } - ); -}; - -registerEvent(removeGameFromDownload, { - name: "removeGameFromDownload", -}); diff --git a/src/main/events/user-preferences/get-user-preferences.ts b/src/main/events/user-preferences/get-user-preferences.ts index 219713eb..03b4ae9d 100644 --- a/src/main/events/user-preferences/get-user-preferences.ts +++ b/src/main/events/user-preferences/get-user-preferences.ts @@ -1,7 +1,7 @@ import { userPreferencesRepository } from "@main/repository"; import { registerEvent } from "../register-event"; -const getUserPreferences = async (_event: Electron.IpcMainInvokeEvent) => +const getUserPreferences = async () => userPreferencesRepository.findOne({ where: { id: 1 }, }); diff --git a/src/main/main.ts b/src/main/main.ts index a98b804c..c54a7e9a 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -5,7 +5,7 @@ import { getNewRepacksFromCPG, getNewRepacksFromUser, // getNewRepacksFromXatab, - // getNewRepacksFromOnlineFix, + getNewRepacksFromOnlineFix, readPipe, startProcessWatcher, writePipe, @@ -79,9 +79,9 @@ const checkForNewRepacks = async () => { getNewRepacksFromCPG( existingRepacks.filter((repack) => repack.repacker === "CPG") ), - // getNewRepacksFromOnlineFix( - // existingRepacks.filter((repack) => repack.repacker === "onlinefix") - // ), + getNewRepacksFromOnlineFix( + existingRepacks.filter((repack) => repack.repacker === "onlinefix") + ), track1337xUsers(existingRepacks), ]).then(() => { repackRepository.count().then((count) => { diff --git a/src/main/services/repack-tracker/cpg-repacks.ts b/src/main/services/repack-tracker/cpg-repacks.ts index 0d7c172b..c4b62c1f 100644 --- a/src/main/services/repack-tracker/cpg-repacks.ts +++ b/src/main/services/repack-tracker/cpg-repacks.ts @@ -19,17 +19,17 @@ export const getNewRepacksFromCPG = async ( try { Array.from(window.document.querySelectorAll(".post")).forEach(($post) => { const $title = $post.querySelector(".entry-title"); - const uploadDate = $post.querySelector("time").getAttribute("datetime"); + const uploadDate = $post.querySelector("time")?.getAttribute("datetime"); const $downloadInfo = Array.from( $post.querySelectorAll(".wp-block-heading") - ).find(($heading) => $heading.textContent.startsWith("Download")); + ).find(($heading) => $heading.textContent?.startsWith("Download")); /* Side note: CPG often misspells "Magnet" as "Magent" */ const $magnet = Array.from($post.querySelectorAll("a")).find( ($a) => - $a.textContent.startsWith("Magnet") || - $a.textContent.startsWith("Magent") + $a.textContent?.startsWith("Magnet") || + $a.textContent?.startsWith("Magent") ); const fileSize = $downloadInfo.textContent diff --git a/src/main/services/repack-tracker/index.ts b/src/main/services/repack-tracker/index.ts index fb345fae..7bd3ce31 100644 --- a/src/main/services/repack-tracker/index.ts +++ b/src/main/services/repack-tracker/index.ts @@ -2,4 +2,4 @@ export * from "./1337x"; export * from "./xatab"; export * from "./cpg-repacks"; export * from "./gog"; -// export * from "./online-fix"; +export * from "./online-fix"; diff --git a/src/main/services/repack-tracker/online-fix.ts b/src/main/services/repack-tracker/online-fix.ts index c572629c..2a69dd70 100644 --- a/src/main/services/repack-tracker/online-fix.ts +++ b/src/main/services/repack-tracker/online-fix.ts @@ -88,7 +88,7 @@ export const getNewRepacksFromOnlineFix = async ( const repacks: GameRepackInput[] = []; const articles = Array.from(document.querySelectorAll(".news")); const totalPages = Number( - document.querySelector("nav > a:nth-child(13)").textContent + document.querySelector("nav > a:nth-child(13)")?.textContent ); try { @@ -186,8 +186,10 @@ export const getNewRepacksFromOnlineFix = async ( }); }) ); - } catch (err) { - logger.error(err.message, { method: "getNewRepacksFromOnlineFix" }); + } catch (err: unknown) { + logger.error((err as Error).message, { + method: "getNewRepacksFromOnlineFix", + }); } const newRepacks = repacks.filter( diff --git a/src/main/services/steam-250.ts b/src/main/services/steam-250.ts index 32ccdc56..bec2c604 100644 --- a/src/main/services/steam-250.ts +++ b/src/main/services/steam-250.ts @@ -7,17 +7,16 @@ export const requestSteam250 = async (path: string) => { const { window } = new JSDOM(response.data); const { document } = window; - return Array.from(document.querySelectorAll(".appline .title a")).map( - ($title: HTMLAnchorElement) => { - const steamGameUrl = $title.href; - if (!steamGameUrl) return null; + return Array.from(document.querySelectorAll(".appline .title a")) + .filter(($title) => Boolean(($title as HTMLAnchorElement).href)) + .map(($title) => { + const steamGameUrl = ($title as HTMLAnchorElement).href; return { title: $title.textContent, objectID: steamGameUrl.split("/").pop(), }; - } - ); + }); }); }; diff --git a/src/main/services/window-manager.ts b/src/main/services/window-manager.ts index 0eea8e96..766eb826 100644 --- a/src/main/services/window-manager.ts +++ b/src/main/services/window-manager.ts @@ -12,13 +12,16 @@ export class WindowManager { // HMR for renderer base on electron-vite cli. // Load the remote URL for development or the local html file for production. if (is.dev && process.env["ELECTRON_RENDERER_URL"]) { - this.mainWindow.loadURL( + this.mainWindow?.loadURL( `${process.env["ELECTRON_RENDERER_URL"]}#/${hash}` ); } else { - this.mainWindow.loadFile(path.join(__dirname, "../renderer/index.html"), { - hash, - }); + this.mainWindow?.loadFile( + path.join(__dirname, "../renderer/index.html"), + { + hash, + } + ); } } @@ -47,7 +50,7 @@ export class WindowManager { this.mainWindow.removeMenu(); this.mainWindow.on("close", () => { - WindowManager.mainWindow.setProgressBar(-1); + WindowManager.mainWindow?.setProgressBar(-1); }); } @@ -55,8 +58,8 @@ export class WindowManager { if (!this.mainWindow) this.createMainWindow(); this.loadURL(hash); - if (this.mainWindow.isMinimized()) this.mainWindow.restore(); - this.mainWindow.focus(); + if (this.mainWindow?.isMinimized()) this.mainWindow.restore(); + this.mainWindow?.focus(); } public static createSystemTray(language: string) { @@ -93,10 +96,10 @@ export class WindowManager { if (process.platform === "win32") { tray.addListener("click", () => { if (this.mainWindow) { - if (WindowManager.mainWindow.isMinimized()) + if (WindowManager.mainWindow?.isMinimized()) WindowManager.mainWindow.restore(); - WindowManager.mainWindow.focus(); + WindowManager.mainWindow?.focus(); return; } diff --git a/src/renderer/src/app.tsx b/src/renderer/src/app.tsx index dd3488cc..6461c0d0 100644 --- a/src/renderer/src/app.tsx +++ b/src/renderer/src/app.tsx @@ -12,7 +12,7 @@ import { import * as styles from "./app.css"; import { themeClass } from "./theme.css"; -import { Outlet, useLocation, useNavigate } from "react-router-dom"; +import { useLocation, useNavigate } from "react-router-dom"; import { setSearch, clearSearch, diff --git a/src/renderer/src/components/async-image/async-image.tsx b/src/renderer/src/components/async-image/async-image.tsx index 857a9942..e3c0ee45 100644 --- a/src/renderer/src/components/async-image/async-image.tsx +++ b/src/renderer/src/components/async-image/async-image.tsx @@ -25,3 +25,5 @@ export const AsyncImage = forwardRef( return ; } ); + +AsyncImage.displayName = "AsyncImage"; diff --git a/src/renderer/src/components/bottom-panel/bottom-panel.tsx b/src/renderer/src/components/bottom-panel/bottom-panel.tsx index df1f49cb..ed9a54ed 100644 --- a/src/renderer/src/components/bottom-panel/bottom-panel.tsx +++ b/src/renderer/src/components/bottom-panel/bottom-panel.tsx @@ -61,7 +61,7 @@ export function BottomPanel() { - v{version} "{VERSION_CODENAME}" + v{version} "{VERSION_CODENAME}" ); diff --git a/yarn.lock b/yarn.lock index 6bf63b34..e708f28d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1024,11 +1024,16 @@ dependencies: "@sentry/types" "7.111.0" -"@sindresorhus/is@^4.0.0": +"@sindresorhus/is@^4.0.0", "@sindresorhus/is@^4.2.0": version "4.6.0" resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz" integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw== +"@sindresorhus/is@^5.2.0", "@sindresorhus/is@^5.3.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-5.6.0.tgz#41dd6093d34652cddb5d5bdeee04eafc33826668" + integrity sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g== + "@sqltools/formatter@^1.2.5": version "1.2.5" resolved "https://registry.npmjs.org/@sqltools/formatter/-/formatter-1.2.5.tgz" @@ -1205,6 +1210,13 @@ dependencies: defer-to-connect "^2.0.0" +"@szmarczak/http-timer@^5.0.1": + version "5.0.1" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-5.0.1.tgz#c7c1bf1141cdd4751b0399c8fc7b8b664cd5be3a" + integrity sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw== + dependencies: + defer-to-connect "^2.0.1" + "@thaunknown/thirty-two@^1.0.3": version "1.0.3" resolved "https://registry.npmjs.org/@thaunknown/thirty-two/-/thirty-two-1.0.3.tgz" @@ -1279,11 +1291,20 @@ dependencies: "@types/node" "*" -"@types/http-cache-semantics@*": +"@types/http-cache-semantics@*", "@types/http-cache-semantics@^4.0.2": version "4.0.4" resolved "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz" integrity sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA== +"@types/jsdom@^21.1.6": + version "21.1.6" + resolved "https://registry.yarnpkg.com/@types/jsdom/-/jsdom-21.1.6.tgz#bcbc7b245787ea863f3da1ef19aa1dcfb9271a1b" + integrity sha512-/7kkMsC+/kMs7gAYmmBR9P0vGTnOoLhQhyhQJSlXGI5bzTHp6xdo0TtKWQAsz6pmSAeVqKSbqeyP6hytqr9FDw== + dependencies: + "@types/node" "*" + "@types/tough-cookie" "*" + parse5 "^7.0.0" + "@types/json-schema@^7.0.12": version "7.0.15" resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz" @@ -1367,6 +1388,11 @@ resolved "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz" integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ== +"@types/tough-cookie@*": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.5.tgz#cb6e2a691b70cb177c6e3ae9c1d2e8b2ea8cd304" + integrity sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA== + "@types/triple-beam@^1.3.2": version "1.3.5" resolved "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz" @@ -1573,6 +1599,11 @@ acorn@^8.11.3, acorn@^8.9.0: resolved "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz" integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== +adm-zip@^0.5.9: + version "0.5.12" + resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.5.12.tgz#87786328e91d54b37358d8a50f954c4cd73ba60b" + integrity sha512-6TVU49mK6KZb4qG6xWaaM4C7sA/sgUMLy/JYMOzkcp3BvVLpW0fXDFQiIzAuxFCt/2+xD7fNIiPFAoLZPhVNLQ== + agent-base@6: version "6.0.2" resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz" @@ -1912,7 +1943,7 @@ braces@^3.0.2: dependencies: fill-range "^7.0.1" -browserslist@^4.22.2: +browserslist@^4.21.1, browserslist@^4.22.2: version "4.23.0" resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz" integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ== @@ -1993,6 +2024,24 @@ cacheable-lookup@^5.0.3: resolved "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz" integrity sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA== +cacheable-lookup@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz#3476a8215d046e5a3202a9209dd13fec1f933a27" + integrity sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w== + +cacheable-request@^10.2.8: + version "10.2.14" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-10.2.14.tgz#eb915b665fda41b79652782df3f553449c406b9d" + integrity sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ== + dependencies: + "@types/http-cache-semantics" "^4.0.2" + get-stream "^6.0.1" + http-cache-semantics "^4.1.1" + keyv "^4.5.3" + mimic-response "^4.0.0" + normalize-url "^8.0.0" + responselike "^3.0.0" + cacheable-request@^7.0.2: version "7.0.4" resolved "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz" @@ -2017,11 +2066,16 @@ call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: get-intrinsic "^1.2.4" set-function-length "^1.2.1" -callsites@^3.0.0: +callsites@^3.0.0, callsites@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== +callsites@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-4.1.0.tgz#de72b98612eed4e1e2564c952498677faa9d86c2" + integrity sha512-aBMbD1Xxay75ViYezwT40aQONfr+pSXTHwNKvIXhXD6+LY3F1dLIcceoC5OZKBVHbXcysz1hL9D2w0JJIMXpUw== + camelcase@^6.2.0: version "6.3.0" resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" @@ -2392,7 +2446,7 @@ deepmerge@4.3.0, deepmerge@^4.2.2: resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.0.tgz" integrity sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og== -defer-to-connect@^2.0.0: +defer-to-connect@^2.0.0, defer-to-connect@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz" integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg== @@ -2495,6 +2549,20 @@ dot-case@^3.0.4: no-case "^3.0.4" tslib "^2.0.3" +dot-prop@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-6.0.1.tgz#fc26b3cf142b9e59b74dbd39ed66ce620c681083" + integrity sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA== + dependencies: + is-obj "^2.0.0" + +dot-prop@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-7.2.0.tgz#468172a3529779814d21a779c1ba2f6d76609809" + integrity sha512-Ol/IPXUARn9CSbkrdV4VJo7uCy1I3VuSiWCaFSg+8BdUOzF9n3jefIpcgAydvUZbTdEBZs2vEiTiS9m61ssiDA== + dependencies: + type-fest "^2.11.2" + dotenv-expand@^5.1.0: version "5.1.0" resolved "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz" @@ -2829,6 +2897,11 @@ eslint-plugin-prettier@^5.0.1: prettier-linter-helpers "^1.0.0" synckit "^0.8.6" +eslint-plugin-react-hooks@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz#4c3e697ad95b77e93f8646aaa1630c1ba607edd3" + integrity sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g== + eslint-plugin-react@^7.33.2: version "7.34.1" resolved "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz" @@ -3118,6 +3191,11 @@ foreground-child@^3.1.0: cross-spawn "^7.0.0" signal-exit "^4.0.1" +form-data-encoder@^2.1.2: + version "2.1.4" + resolved "https://registry.yarnpkg.com/form-data-encoder/-/form-data-encoder-2.1.4.tgz#261ea35d2a70d48d30ec7a9603130fa5515e9cd5" + integrity sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw== + form-data@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz" @@ -3204,6 +3282,14 @@ functions-have-names@^1.2.3: resolved "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== +generative-bayesian-network@^2.1.50: + version "2.1.50" + resolved "https://registry.yarnpkg.com/generative-bayesian-network/-/generative-bayesian-network-2.1.50.tgz#a576130befe0e30ccfebe5280fb2550649abadc9" + integrity sha512-iVmmQ4lpa41xqtrg6cbWuH1Qa2+C6tndb2dJmJazBEIQcnvz29ZYxbnqB1DAvbico3nGIVzF2Hvj2gZU9EewAQ== + dependencies: + adm-zip "^0.5.9" + tslib "^2.4.0" + gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" @@ -3237,6 +3323,11 @@ get-stream@^5.1.0: dependencies: pump "^3.0.0" +get-stream@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + get-symbol-description@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz" @@ -3338,6 +3429,19 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" +got-scraping@^4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/got-scraping/-/got-scraping-4.0.5.tgz#e1cab8ff2420d9c9f406bac405c10e8b324ec4ec" + integrity sha512-g+cMC5WOVOHd6S3JdTtm+zCwpWdd3jA1MYnkOwVF7MpbKP7EWv7ORUfXDcG3gTANJ1zYj9XffCrAjbH8ssHmfw== + dependencies: + got "^13.0.0" + header-generator "^2.1.41" + http2-wrapper "^2.2.0" + mimic-response "^4.0.0" + ow "^1.1.1" + quick-lru "^7.0.0" + tslib "^2.6.2" + got@^11.8.5: version "11.8.6" resolved "https://registry.npmjs.org/got/-/got-11.8.6.tgz" @@ -3355,6 +3459,23 @@ got@^11.8.5: p-cancelable "^2.0.0" responselike "^2.0.0" +got@^13.0.0: + version "13.0.0" + resolved "https://registry.yarnpkg.com/got/-/got-13.0.0.tgz#a2402862cef27a5d0d1b07c0fb25d12b58175422" + integrity sha512-XfBk1CxOOScDcMr9O1yKkNaQyy865NbYs+F7dr4H0LZMVgCj2Le59k6PqbNHoL5ToeaEQUYh6c6yMfVcc6SJxA== + dependencies: + "@sindresorhus/is" "^5.2.0" + "@szmarczak/http-timer" "^5.0.1" + cacheable-lookup "^7.0.0" + cacheable-request "^10.2.8" + decompress-response "^6.0.0" + form-data-encoder "^2.1.2" + get-stream "^6.0.1" + http2-wrapper "^2.1.10" + lowercase-keys "^3.0.0" + p-cancelable "^3.0.0" + responselike "^3.0.0" + graceful-fs@^4.1.6, graceful-fs@^4.2.0: version "4.2.11" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" @@ -3411,6 +3532,16 @@ hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: dependencies: function-bind "^1.1.2" +header-generator@^2.1.41: + version "2.1.50" + resolved "https://registry.yarnpkg.com/header-generator/-/header-generator-2.1.50.tgz#338fd7d92131dcaf71918b6ac8b9a26d6bb6acc0" + integrity sha512-Z37QBqcPzEqCCFQcOv1Kth1My3h4Vx+2V+aBipjrefZ2MFbVfYB/mo1v+OxiEJir5zSp9rX/z+BoqTuSAIGBLQ== + dependencies: + browserslist "^4.21.1" + generative-bayesian-network "^2.1.50" + ow "^0.28.1" + tslib "^2.4.0" + highlight.js@^10.7.1: version "10.7.3" resolved "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz" @@ -3444,7 +3575,7 @@ html-parse-stringify@^3.0.1: dependencies: void-elements "3.1.0" -http-cache-semantics@^4.0.0: +http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.1: version "4.1.1" resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz" integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== @@ -3474,6 +3605,14 @@ http2-wrapper@^1.0.0-beta.5.2: quick-lru "^5.1.1" resolve-alpn "^1.0.0" +http2-wrapper@^2.1.10, http2-wrapper@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-2.2.1.tgz#310968153dcdedb160d8b72114363ef5fce1f64a" + integrity sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ== + dependencies: + quick-lru "^5.1.1" + resolve-alpn "^1.2.0" + https-proxy-agent@^5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz" @@ -3700,6 +3839,11 @@ is-number@^7.0.0: resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== +is-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" + integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== + is-path-inside@^3.0.3: version "3.0.3" resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz" @@ -3973,6 +4117,11 @@ lodash-es@^4.17.21: resolved "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz" integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== +lodash.isequal@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== + lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz" @@ -4026,6 +4175,11 @@ lowercase-keys@^2.0.0: resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz" integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== +lowercase-keys@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-3.0.0.tgz#c5e7d442e37ead247ae9db117a9d0a467c89d4f2" + integrity sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ== + lru-cache@^10.2.0: version "10.2.0" resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz" @@ -4115,6 +4269,11 @@ mimic-response@^3.1.0: resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz" integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== +mimic-response@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-4.0.0.tgz#35468b19e7c75d10f5165ea25e75a5ceea7cf70f" + integrity sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg== + minimatch@9.0.3, minimatch@^9.0.1: version "9.0.3" resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz" @@ -4274,6 +4433,11 @@ normalize-url@^6.0.1: resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz" integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== +normalize-url@^8.0.0: + version "8.0.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-8.0.1.tgz#9b7d96af9836577c58f5883e939365fa15623a4a" + integrity sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w== + nwsapi@^2.2.7: version "2.2.8" resolved "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.8.tgz" @@ -4372,11 +4536,38 @@ outdent@^0.8.0: resolved "https://registry.npmjs.org/outdent/-/outdent-0.8.0.tgz" integrity sha512-KiOAIsdpUTcAXuykya5fnVVT+/5uS0Q1mrkRHcF89tpieSmY33O/tmc54CqwA+bfhbtEfZUNLHaPUiB9X3jt1A== +ow@^0.28.1: + version "0.28.2" + resolved "https://registry.yarnpkg.com/ow/-/ow-0.28.2.tgz#782b28102124e665c49ec7725e2066a129acf6bf" + integrity sha512-dD4UpyBh/9m4X2NVjA+73/ZPBRF+uF4zIMFvvQsabMiEK8x41L3rQ8EENOi35kyyoaJwNxEeJcP6Fj1H4U409Q== + dependencies: + "@sindresorhus/is" "^4.2.0" + callsites "^3.1.0" + dot-prop "^6.0.1" + lodash.isequal "^4.5.0" + vali-date "^1.0.0" + +ow@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ow/-/ow-1.1.1.tgz#354a0f7df9d8d0cf961b29116daf972ef6be1632" + integrity sha512-sJBRCbS5vh1Jp9EOgwp1Ws3c16lJrUkJYlvWTYC03oyiYVwS/ns7lKRWow4w4XjDyTrA2pplQv4B2naWSR6yDA== + dependencies: + "@sindresorhus/is" "^5.3.0" + callsites "^4.0.0" + dot-prop "^7.2.0" + lodash.isequal "^4.5.0" + vali-date "^1.0.0" + p-cancelable@^2.0.0: version "2.1.1" resolved "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz" integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg== +p-cancelable@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-3.0.0.tgz#63826694b54d61ca1c20ebcb6d3ecf5e14cd8050" + integrity sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw== + p-limit@^3.0.2: version "3.1.0" resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" @@ -4437,7 +4628,7 @@ parse5@^6.0.1: resolved "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz" integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== -parse5@^7.1.2: +parse5@^7.0.0, parse5@^7.1.2: version "7.1.2" resolved "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz" integrity sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw== @@ -4629,6 +4820,11 @@ quick-lru@^5.1.1: resolved "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz" integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== +quick-lru@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-7.0.0.tgz#447f6925b33ae4d2d637e211967d74bae4b99c3f" + integrity sha512-MX8gB7cVYTrYcFfAnfLlhRd0+Toyl8yX8uBx1MrX7K0jegiz9TumwOK27ldXrgDlHRdVi+MqU9Ssw6dr4BNreg== + rc@^1.2.7: version "1.2.8" resolved "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz" @@ -4784,7 +4980,7 @@ reselect@^5.0.1: resolved "https://registry.npmjs.org/reselect/-/reselect-5.1.0.tgz" integrity sha512-aw7jcGLDpSgNDyWBQLv2cedml85qd95/iszJjN988zX1t7AVRJi19d9kto5+W7oCfQ94gyo40dVbT6g2k4/kXg== -resolve-alpn@^1.0.0: +resolve-alpn@^1.0.0, resolve-alpn@^1.2.0: version "1.2.1" resolved "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz" integrity sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g== @@ -4810,6 +5006,13 @@ responselike@^2.0.0: dependencies: lowercase-keys "^2.0.0" +responselike@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-3.0.0.tgz#20decb6c298aff0dbee1c355ca95461d42823626" + integrity sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg== + dependencies: + lowercase-keys "^3.0.0" + retry@^0.12.0: version "0.12.0" resolved "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz" @@ -5403,7 +5606,7 @@ ts-api-utils@^1.0.1: resolved "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz" integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== -tslib@^2.0.3, tslib@^2.5.0, tslib@^2.6.2: +tslib@^2.0.3, tslib@^2.4.0, tslib@^2.5.0, tslib@^2.6.2: version "2.6.2" resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz" integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== @@ -5432,6 +5635,11 @@ type-fest@^0.20.2: resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== +type-fest@^2.11.2: + version "2.19.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" + integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== + typed-array-buffer@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz" @@ -5587,6 +5795,11 @@ uuid@^9.0.0: resolved "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz" integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== +vali-date@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/vali-date/-/vali-date-1.0.0.tgz#1b904a59609fb328ef078138420934f6b86709a6" + integrity sha512-sgECfZthyaCKW10N0fm27cg8HYTFK5qMWgypqkXMQ4Wbl/zZKx7xZICgcoxIIE+WFAP/MBL2EFwC/YvLxw3Zeg== + verror@^1.10.0: version "1.10.1" resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.1.tgz#4bf09eeccf4563b109ed4b3d458380c972b0cdeb" @@ -5726,6 +5939,11 @@ which@^2.0.1: dependencies: isexe "^2.0.0" +windows-1251@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/windows-1251/-/windows-1251-3.0.4.tgz#984b9f2e76befd9ec2e825f9fe77b681fadcdb55" + integrity sha512-H6W68MVertlR74xVuwa2pdQ1jR5qksk+oZX6QXFhL5OYj/ZZxViob8UyGLfXPwsCijuaV7NUYOYkK0oXSaWW5g== + winston-transport@^4.7.0: version "4.7.0" resolved "https://registry.npmjs.org/winston-transport/-/winston-transport-4.7.0.tgz" From 1c59e98fbf458097e7080d539da880b7ab917bd6 Mon Sep 17 00:00:00 2001 From: Netflixy Date: Thu, 25 Apr 2024 23:24:50 +0200 Subject: [PATCH 057/140] fix: fix french terms in translation --- src/locales/fr/translation.json | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/locales/fr/translation.json b/src/locales/fr/translation.json index 154186be..3e247b07 100644 --- a/src/locales/fr/translation.json +++ b/src/locales/fr/translation.json @@ -30,8 +30,8 @@ "bottom_panel": { "no_downloads_in_progress": "Aucun téléchargement en cours", "downloading_metadata": "Téléchargement des métadonnées de {{title}}…", - "checking_files": "Vérification des fichiers de {{title}}… ({{percentage}} complet)", - "downloading": "Téléchargement de {{title}}… ({{percentage}} complet) - Conclusion dans {{eta}} - {{speed}}" + "checking_files": "Vérification des fichiers de {{title}}… ({{percentage}} terminé)", + "downloading": "Téléchargement de {{title}}… ({{percentage}} terminé) - Fin dans {{eta}} - {{speed}}" }, "game_details": { "open_download_options": "Ouvrir les options de téléchargement", @@ -45,15 +45,15 @@ "remove": "Supprimer", "remove_from_list": "Retirer", "space_left_on_disk": "{{space}} restant sur le disque", - "eta": "Conclusion dans {{eta}}", + "eta": "Fin dans {{eta}}", "downloading_metadata": "Téléchargement des métadonnées en cours…", "checking_files": "Vérification des fichiers…", - "filter": "Filtrer les réductions", + "filter": "Filtrer les repacks", "requirements": "Configuration requise", "minimum": "Minimum", "recommended": "Recommandée", - "no_minimum_requirements": "{{title}} ne fournit pas d'informations sur les exigences minimales", - "no_recommended_requirements": "{{title}} ne fournit pas d'informations sur les exigences recommandées", + "no_minimum_requirements": "{{title}} ne fournit pas d'informations sur les configurations minimales", + "no_recommended_requirements": "{{title}} ne fournit pas d'informations sur les configurations recommandées", "paused_progress": "{{progress}} (En pause)", "release_date": "Sorti le {{date}}", "publisher": "Édité par {{publisher}}", @@ -72,21 +72,21 @@ "not_played_yet": "Vous n'avez pas encore joué à {{title}}", "close": "Fermer", "deleting": "Suppression du programme d'installation…", - "playing_now": "Je joue maintenant", - "last_time_played": "Dernière lecture {{période}}" + "playing_now": "Jeu en cours", + "last_time_played": "Dernièrement joué {{période}}" }, "activation": { "title": "Activer Hydra", "installation_id": "ID d'installation :", "enter_activation_code": "Entrez votre code d'activation", - "message": "Si vous ne savez pas où demander cela, vous ne devriez pas l'avoir.", + "message": "Si vous ne savez pas où demander ceci, vous ne devriez pas l'avoir.", "activate": "Activer", "loading": "Chargement en cours…" }, "downloads": { "resume": "Reprendre", "pause": "Pause", - "eta": "Conclusion dans {{eta}}", + "eta": "Fin dans {{eta}}", "paused": "En pause", "verifying": "Vérification en cours…", "completed_at": "Terminé en {{date}}", @@ -111,16 +111,16 @@ "change": "Mettre à jour", "notifications": "Notifications", "enable_download_notifications": "Quand un téléchargement est terminé", - "enable_repack_list_notifications": "Quand une nouvelle réduction est ajoutée", + "enable_repack_list_notifications": "Quand un nouveau repack est ajouté", "telemetry": "Télémétrie", "telemetry_description": "Activer les statistiques d'utilisation anonymes" }, "notifications": { "download_complete": "Téléchargement terminé", "game_ready_to_install": "{{title}} est prêt à être installé", - "repack_list_updated": "Liste de réductions mise à jour", - "repack_count_one": "{{count}} réduction ajoutée", - "repack_count_other": "{{count}} réductions ajoutées" + "repack_list_updated": "Liste de repacks mise à jour", + "repack_count_one": "{{count}} repack ajouté", + "repack_count_other": "{{count}} repacks ajoutés" }, "system_tray": { "open": "Ouvrir Hydra", From 5c9e1099b4868523d24212f042b83068b0ceb9b2 Mon Sep 17 00:00:00 2001 From: Netflixy Date: Thu, 25 Apr 2024 23:24:50 +0200 Subject: [PATCH 058/140] fix: fix french terms in translation --- src/locales/fr/translation.json | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/locales/fr/translation.json b/src/locales/fr/translation.json index 154186be..3e247b07 100644 --- a/src/locales/fr/translation.json +++ b/src/locales/fr/translation.json @@ -30,8 +30,8 @@ "bottom_panel": { "no_downloads_in_progress": "Aucun téléchargement en cours", "downloading_metadata": "Téléchargement des métadonnées de {{title}}…", - "checking_files": "Vérification des fichiers de {{title}}… ({{percentage}} complet)", - "downloading": "Téléchargement de {{title}}… ({{percentage}} complet) - Conclusion dans {{eta}} - {{speed}}" + "checking_files": "Vérification des fichiers de {{title}}… ({{percentage}} terminé)", + "downloading": "Téléchargement de {{title}}… ({{percentage}} terminé) - Fin dans {{eta}} - {{speed}}" }, "game_details": { "open_download_options": "Ouvrir les options de téléchargement", @@ -45,15 +45,15 @@ "remove": "Supprimer", "remove_from_list": "Retirer", "space_left_on_disk": "{{space}} restant sur le disque", - "eta": "Conclusion dans {{eta}}", + "eta": "Fin dans {{eta}}", "downloading_metadata": "Téléchargement des métadonnées en cours…", "checking_files": "Vérification des fichiers…", - "filter": "Filtrer les réductions", + "filter": "Filtrer les repacks", "requirements": "Configuration requise", "minimum": "Minimum", "recommended": "Recommandée", - "no_minimum_requirements": "{{title}} ne fournit pas d'informations sur les exigences minimales", - "no_recommended_requirements": "{{title}} ne fournit pas d'informations sur les exigences recommandées", + "no_minimum_requirements": "{{title}} ne fournit pas d'informations sur les configurations minimales", + "no_recommended_requirements": "{{title}} ne fournit pas d'informations sur les configurations recommandées", "paused_progress": "{{progress}} (En pause)", "release_date": "Sorti le {{date}}", "publisher": "Édité par {{publisher}}", @@ -72,21 +72,21 @@ "not_played_yet": "Vous n'avez pas encore joué à {{title}}", "close": "Fermer", "deleting": "Suppression du programme d'installation…", - "playing_now": "Je joue maintenant", - "last_time_played": "Dernière lecture {{période}}" + "playing_now": "Jeu en cours", + "last_time_played": "Dernièrement joué {{période}}" }, "activation": { "title": "Activer Hydra", "installation_id": "ID d'installation :", "enter_activation_code": "Entrez votre code d'activation", - "message": "Si vous ne savez pas où demander cela, vous ne devriez pas l'avoir.", + "message": "Si vous ne savez pas où demander ceci, vous ne devriez pas l'avoir.", "activate": "Activer", "loading": "Chargement en cours…" }, "downloads": { "resume": "Reprendre", "pause": "Pause", - "eta": "Conclusion dans {{eta}}", + "eta": "Fin dans {{eta}}", "paused": "En pause", "verifying": "Vérification en cours…", "completed_at": "Terminé en {{date}}", @@ -111,16 +111,16 @@ "change": "Mettre à jour", "notifications": "Notifications", "enable_download_notifications": "Quand un téléchargement est terminé", - "enable_repack_list_notifications": "Quand une nouvelle réduction est ajoutée", + "enable_repack_list_notifications": "Quand un nouveau repack est ajouté", "telemetry": "Télémétrie", "telemetry_description": "Activer les statistiques d'utilisation anonymes" }, "notifications": { "download_complete": "Téléchargement terminé", "game_ready_to_install": "{{title}} est prêt à être installé", - "repack_list_updated": "Liste de réductions mise à jour", - "repack_count_one": "{{count}} réduction ajoutée", - "repack_count_other": "{{count}} réductions ajoutées" + "repack_list_updated": "Liste de repacks mise à jour", + "repack_count_one": "{{count}} repack ajouté", + "repack_count_other": "{{count}} repacks ajoutés" }, "system_tray": { "open": "Ouvrir Hydra", From 5cb81cd54fbcb610f5a3c6a09c77be8dc35c50b3 Mon Sep 17 00:00:00 2001 From: Zamitto Date: Tue, 23 Apr 2024 21:10:15 -0300 Subject: [PATCH 059/140] feat: use psList on windows (~25ms vs ~320ms) --- src/main/helpers/ps.ts | 7 ------- src/main/services/process-watcher.ts | 17 +++++++++-------- yarn.lock | 2 +- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/main/helpers/ps.ts b/src/main/helpers/ps.ts index f7ce3391..5a30a9ed 100644 --- a/src/main/helpers/ps.ts +++ b/src/main/helpers/ps.ts @@ -1,12 +1,5 @@ import psList from "ps-list"; -import { tasklist } from "tasklist"; export const getProcesses = async () => { - if (process.platform === "win32") { - return tasklist().then((tasks) => - tasks.map((task) => ({ ...task, name: task.imageName })) - ); - } - return psList(); }; diff --git a/src/main/services/process-watcher.ts b/src/main/services/process-watcher.ts index 96244a60..c67f6815 100644 --- a/src/main/services/process-watcher.ts +++ b/src/main/services/process-watcher.ts @@ -1,7 +1,7 @@ import path from "node:path"; import { IsNull, Not } from "typeorm"; - +import { exec } from "child_process" import { gameRepository } from "@main/repository"; import { getProcesses } from "@main/helpers"; import { WindowManager } from "./window-manager"; @@ -14,13 +14,21 @@ export const startProcessWatcher = async () => { // eslint-disable-next-line no-constant-condition while (true) { + await sleep(sleepTime); + const games = await gameRepository.find({ where: { executablePath: Not(IsNull()), }, }); + if (games.length == 0) { + continue; + } + + console.time("getProcesses") const processes = await getProcesses(); + console.timeEnd("getProcesses") for (const game of games) { const gameProcess = processes.find((runningProcess) => { @@ -55,15 +63,10 @@ export const startProcessWatcher = async () => { gameRepository.update(game.id, { lastTimePlayed: new Date().toUTCString(), }); - - gamesPlaytime.set(game.id, performance.now()); - await sleep(sleepTime); - continue; } gamesPlaytime.set(game.id, performance.now()); - await sleep(sleepTime); continue; } @@ -73,8 +76,6 @@ export const startProcessWatcher = async () => { WindowManager.mainWindow.webContents.send("on-game-close", game.id); } } - - await sleep(sleepTime); } } }; diff --git a/yarn.lock b/yarn.lock index 8b36bcdb..c6450c09 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8866,7 +8866,7 @@ proxy-from-env@^1.1.0: ps-list@^8.1.1: version "8.1.1" - resolved "https://registry.npmjs.org/ps-list/-/ps-list-8.1.1.tgz" + resolved "https://registry.yarnpkg.com/ps-list/-/ps-list-8.1.1.tgz#9ff1952b26a9a07fcc05270407e60544237ae581" integrity sha512-OPS9kEJYVmiO48u/B9qneqhkMvgCxT+Tm28VCEJpheTpl8cJ0ffZRRNgS5mrQRTrX5yRTpaJ+hRDeefXYmmorQ== psl@^1.1.33: From ecac6376d75da72db0732fd73a14e8a8d1e19cf9 Mon Sep 17 00:00:00 2001 From: Zamitto Date: Tue, 23 Apr 2024 21:10:15 -0300 Subject: [PATCH 060/140] feat: use psList on windows (~25ms vs ~320ms) --- src/main/helpers/ps.ts | 7 ------- src/main/services/process-watcher.ts | 17 +++++++++-------- yarn.lock | 2 +- 3 files changed, 10 insertions(+), 16 deletions(-) diff --git a/src/main/helpers/ps.ts b/src/main/helpers/ps.ts index f7ce3391..5a30a9ed 100644 --- a/src/main/helpers/ps.ts +++ b/src/main/helpers/ps.ts @@ -1,12 +1,5 @@ import psList from "ps-list"; -import { tasklist } from "tasklist"; export const getProcesses = async () => { - if (process.platform === "win32") { - return tasklist().then((tasks) => - tasks.map((task) => ({ ...task, name: task.imageName })) - ); - } - return psList(); }; diff --git a/src/main/services/process-watcher.ts b/src/main/services/process-watcher.ts index 96244a60..c67f6815 100644 --- a/src/main/services/process-watcher.ts +++ b/src/main/services/process-watcher.ts @@ -1,7 +1,7 @@ import path from "node:path"; import { IsNull, Not } from "typeorm"; - +import { exec } from "child_process" import { gameRepository } from "@main/repository"; import { getProcesses } from "@main/helpers"; import { WindowManager } from "./window-manager"; @@ -14,13 +14,21 @@ export const startProcessWatcher = async () => { // eslint-disable-next-line no-constant-condition while (true) { + await sleep(sleepTime); + const games = await gameRepository.find({ where: { executablePath: Not(IsNull()), }, }); + if (games.length == 0) { + continue; + } + + console.time("getProcesses") const processes = await getProcesses(); + console.timeEnd("getProcesses") for (const game of games) { const gameProcess = processes.find((runningProcess) => { @@ -55,15 +63,10 @@ export const startProcessWatcher = async () => { gameRepository.update(game.id, { lastTimePlayed: new Date().toUTCString(), }); - - gamesPlaytime.set(game.id, performance.now()); - await sleep(sleepTime); - continue; } gamesPlaytime.set(game.id, performance.now()); - await sleep(sleepTime); continue; } @@ -73,8 +76,6 @@ export const startProcessWatcher = async () => { WindowManager.mainWindow.webContents.send("on-game-close", game.id); } } - - await sleep(sleepTime); } } }; diff --git a/yarn.lock b/yarn.lock index 8b36bcdb..c6450c09 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8866,7 +8866,7 @@ proxy-from-env@^1.1.0: ps-list@^8.1.1: version "8.1.1" - resolved "https://registry.npmjs.org/ps-list/-/ps-list-8.1.1.tgz" + resolved "https://registry.yarnpkg.com/ps-list/-/ps-list-8.1.1.tgz#9ff1952b26a9a07fcc05270407e60544237ae581" integrity sha512-OPS9kEJYVmiO48u/B9qneqhkMvgCxT+Tm28VCEJpheTpl8cJ0ffZRRNgS5mrQRTrX5yRTpaJ+hRDeefXYmmorQ== psl@^1.1.33: From 8a496d20effdd19ff9ed32be63b8d1ccfae9aaf2 Mon Sep 17 00:00:00 2001 From: Zamitto Date: Tue, 23 Apr 2024 21:42:35 -0300 Subject: [PATCH 061/140] feat: add total loop time log --- src/main/services/process-watcher.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/services/process-watcher.ts b/src/main/services/process-watcher.ts index c67f6815..89e49b51 100644 --- a/src/main/services/process-watcher.ts +++ b/src/main/services/process-watcher.ts @@ -16,6 +16,7 @@ export const startProcessWatcher = async () => { while (true) { await sleep(sleepTime); + console.log("loopTotalTime") const games = await gameRepository.find({ where: { executablePath: Not(IsNull()), @@ -31,13 +32,13 @@ export const startProcessWatcher = async () => { console.timeEnd("getProcesses") for (const game of games) { - const gameProcess = processes.find((runningProcess) => { - const basename = path.win32.basename(game.executablePath); + const basename = path.win32.basename(game.executablePath); const basenameWithoutExtension = path.win32.basename( game.executablePath, path.extname(game.executablePath) ); + const gameProcess = processes.find((runningProcess) => { if (process.platform === "win32") { return runningProcess.name === basename; } From 2675641f7bd70cd22e293d5800d065d5eed6c413 Mon Sep 17 00:00:00 2001 From: Zamitto Date: Tue, 23 Apr 2024 21:42:35 -0300 Subject: [PATCH 062/140] feat: add total loop time log --- src/main/services/process-watcher.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/services/process-watcher.ts b/src/main/services/process-watcher.ts index c67f6815..89e49b51 100644 --- a/src/main/services/process-watcher.ts +++ b/src/main/services/process-watcher.ts @@ -16,6 +16,7 @@ export const startProcessWatcher = async () => { while (true) { await sleep(sleepTime); + console.log("loopTotalTime") const games = await gameRepository.find({ where: { executablePath: Not(IsNull()), @@ -31,13 +32,13 @@ export const startProcessWatcher = async () => { console.timeEnd("getProcesses") for (const game of games) { - const gameProcess = processes.find((runningProcess) => { - const basename = path.win32.basename(game.executablePath); + const basename = path.win32.basename(game.executablePath); const basenameWithoutExtension = path.win32.basename( game.executablePath, path.extname(game.executablePath) ); + const gameProcess = processes.find((runningProcess) => { if (process.platform === "win32") { return runningProcess.name === basename; } From efab6a7c30fcefc311085c966fa5f498320a94aa Mon Sep 17 00:00:00 2001 From: Zamitto Date: Tue, 23 Apr 2024 21:44:09 -0300 Subject: [PATCH 063/140] format with prettier --- src/main/services/process-watcher.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/main/services/process-watcher.ts b/src/main/services/process-watcher.ts index 89e49b51..2ed46cd0 100644 --- a/src/main/services/process-watcher.ts +++ b/src/main/services/process-watcher.ts @@ -1,7 +1,6 @@ import path from "node:path"; import { IsNull, Not } from "typeorm"; -import { exec } from "child_process" import { gameRepository } from "@main/repository"; import { getProcesses } from "@main/helpers"; import { WindowManager } from "./window-manager"; @@ -16,7 +15,7 @@ export const startProcessWatcher = async () => { while (true) { await sleep(sleepTime); - console.log("loopTotalTime") + console.log("loopTotalTime"); const games = await gameRepository.find({ where: { executablePath: Not(IsNull()), @@ -27,16 +26,16 @@ export const startProcessWatcher = async () => { continue; } - console.time("getProcesses") + console.time("getProcesses"); const processes = await getProcesses(); - console.timeEnd("getProcesses") + console.timeEnd("getProcesses"); for (const game of games) { const basename = path.win32.basename(game.executablePath); - const basenameWithoutExtension = path.win32.basename( - game.executablePath, - path.extname(game.executablePath) - ); + const basenameWithoutExtension = path.win32.basename( + game.executablePath, + path.extname(game.executablePath) + ); const gameProcess = processes.find((runningProcess) => { if (process.platform === "win32") { From 1620437d1e107520f7c69d63147a9d4f4df32147 Mon Sep 17 00:00:00 2001 From: Zamitto Date: Tue, 23 Apr 2024 21:44:09 -0300 Subject: [PATCH 064/140] format with prettier --- src/main/services/process-watcher.ts | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/main/services/process-watcher.ts b/src/main/services/process-watcher.ts index 89e49b51..2ed46cd0 100644 --- a/src/main/services/process-watcher.ts +++ b/src/main/services/process-watcher.ts @@ -1,7 +1,6 @@ import path from "node:path"; import { IsNull, Not } from "typeorm"; -import { exec } from "child_process" import { gameRepository } from "@main/repository"; import { getProcesses } from "@main/helpers"; import { WindowManager } from "./window-manager"; @@ -16,7 +15,7 @@ export const startProcessWatcher = async () => { while (true) { await sleep(sleepTime); - console.log("loopTotalTime") + console.log("loopTotalTime"); const games = await gameRepository.find({ where: { executablePath: Not(IsNull()), @@ -27,16 +26,16 @@ export const startProcessWatcher = async () => { continue; } - console.time("getProcesses") + console.time("getProcesses"); const processes = await getProcesses(); - console.timeEnd("getProcesses") + console.timeEnd("getProcesses"); for (const game of games) { const basename = path.win32.basename(game.executablePath); - const basenameWithoutExtension = path.win32.basename( - game.executablePath, - path.extname(game.executablePath) - ); + const basenameWithoutExtension = path.win32.basename( + game.executablePath, + path.extname(game.executablePath) + ); const gameProcess = processes.find((runningProcess) => { if (process.platform === "win32") { From cb82424eb2420ae55c675b983263d87411f7da6e Mon Sep 17 00:00:00 2001 From: Zamitto Date: Tue, 23 Apr 2024 22:21:07 -0300 Subject: [PATCH 065/140] correctly print time logs --- src/main/services/process-watcher.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main/services/process-watcher.ts b/src/main/services/process-watcher.ts index 2ed46cd0..c040373a 100644 --- a/src/main/services/process-watcher.ts +++ b/src/main/services/process-watcher.ts @@ -15,7 +15,7 @@ export const startProcessWatcher = async () => { while (true) { await sleep(sleepTime); - console.log("loopTotalTime"); + console.time("loopTotalTime"); const games = await gameRepository.find({ where: { executablePath: Not(IsNull()), @@ -66,16 +66,13 @@ export const startProcessWatcher = async () => { } gamesPlaytime.set(game.id, performance.now()); - - continue; - } - - if (gamesPlaytime.has(game.id)) { + } else if (gamesPlaytime.has(game.id)) { gamesPlaytime.delete(game.id); if (WindowManager.mainWindow) { WindowManager.mainWindow.webContents.send("on-game-close", game.id); } } } + console.timeEnd("loopTotalTime"); } }; From 854b23e4ef164d396ada17bb6cedc6af5fd9b067 Mon Sep 17 00:00:00 2001 From: Zamitto Date: Tue, 23 Apr 2024 22:21:07 -0300 Subject: [PATCH 066/140] correctly print time logs --- src/main/services/process-watcher.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main/services/process-watcher.ts b/src/main/services/process-watcher.ts index 2ed46cd0..c040373a 100644 --- a/src/main/services/process-watcher.ts +++ b/src/main/services/process-watcher.ts @@ -15,7 +15,7 @@ export const startProcessWatcher = async () => { while (true) { await sleep(sleepTime); - console.log("loopTotalTime"); + console.time("loopTotalTime"); const games = await gameRepository.find({ where: { executablePath: Not(IsNull()), @@ -66,16 +66,13 @@ export const startProcessWatcher = async () => { } gamesPlaytime.set(game.id, performance.now()); - - continue; - } - - if (gamesPlaytime.has(game.id)) { + } else if (gamesPlaytime.has(game.id)) { gamesPlaytime.delete(game.id); if (WindowManager.mainWindow) { WindowManager.mainWindow.webContents.send("on-game-close", game.id); } } } + console.timeEnd("loopTotalTime"); } }; From e4133e9a907c9aaf8a5f212c129419cc7524dc7e Mon Sep 17 00:00:00 2001 From: Zamitto Date: Thu, 25 Apr 2024 21:40:46 -0300 Subject: [PATCH 067/140] feat: run fastfile binary from resources folder feat: run process watcher each 300ms feat: add build step to copy fastlist from node_modules feat: create postinstall script to copy fastlist binary remove debug logs --- .gitignore | 3 +++ package.json | 3 ++- postinstall.py | 5 +++++ src/main/events/library/close-game.ts | 3 ++- src/main/helpers/ps.ts | 31 +++++++++++++++++++++++++-- src/main/services/process-watcher.ts | 9 +++----- 6 files changed, 44 insertions(+), 10 deletions(-) create mode 100644 postinstall.py diff --git a/.gitignore b/.gitignore index 0d0363c8..360a16b4 100644 --- a/.gitignore +++ b/.gitignore @@ -106,3 +106,6 @@ resources/dist/ # Sentry Config File .env.sentry-build-plugin + +# Fastlist binary +resources/fastlist.exe diff --git a/package.json b/package.json index 84853898..381dd285 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,8 @@ "make": "electron-forge make", "publish": "electron-forge publish", "lint": "eslint .", - "format": "prettier . --write" + "format": "prettier . --write", + "postinstall": "python3 ./postinstall.py" }, "devDependencies": { "@electron-forge/cli": "^7.3.0", diff --git a/postinstall.py b/postinstall.py new file mode 100644 index 00000000..3fb85d8d --- /dev/null +++ b/postinstall.py @@ -0,0 +1,5 @@ +import shutil +import platform + +if platform.system() == "Windows": + shutil.copy("node_modules/ps-list/vendor/fastlist-0.3.0-x64.exe", "resources/fastlist.exe") diff --git a/src/main/events/library/close-game.ts b/src/main/events/library/close-game.ts index 0d556925..586253b9 100644 --- a/src/main/events/library/close-game.ts +++ b/src/main/events/library/close-game.ts @@ -4,12 +4,13 @@ import { gameRepository } from "@main/repository"; import { registerEvent } from "../register-event"; import { getProcesses } from "@main/helpers"; +import { app } from "electron"; const closeGame = async ( _event: Electron.IpcMainInvokeEvent, gameId: number ) => { - const processes = await getProcesses(); + const processes = await getProcesses(app.isPackaged); const game = await gameRepository.findOne({ where: { id: gameId } }); const gameProcess = processes.find((runningProcess) => { diff --git a/src/main/helpers/ps.ts b/src/main/helpers/ps.ts index 5a30a9ed..449d103f 100644 --- a/src/main/helpers/ps.ts +++ b/src/main/helpers/ps.ts @@ -1,5 +1,32 @@ import psList from "ps-list"; +import path from "node:path"; +import childProcess from "node:child_process"; +import { promisify } from "node:util"; -export const getProcesses = async () => { - return psList(); +const TEN_MEGABYTES = 1000 * 1000 * 10; +const execFile = promisify(childProcess.execFile); + +export const getProcesses = async (isPackaged: boolean) => { + if (process.platform == "win32") { + const binaryPath = isPackaged + ? path.join(process.resourcesPath, "fastlist.exe") + : path.join(__dirname, "..", "..", "resources", "fastlist.exe"); + + const { stdout } = await execFile(binaryPath, { + maxBuffer: TEN_MEGABYTES, + windowsHide: true, + }); + + return stdout + .trim() + .split("\r\n") + .map((line) => line.split("\t")) + .map(([pid, ppid, name]) => ({ + pid: Number.parseInt(pid, 10), + ppid: Number.parseInt(ppid, 10), + name, + })); + } else { + return psList(); + } }; diff --git a/src/main/services/process-watcher.ts b/src/main/services/process-watcher.ts index c040373a..0668c1db 100644 --- a/src/main/services/process-watcher.ts +++ b/src/main/services/process-watcher.ts @@ -4,18 +4,18 @@ import { IsNull, Not } from "typeorm"; import { gameRepository } from "@main/repository"; import { getProcesses } from "@main/helpers"; import { WindowManager } from "./window-manager"; +import { app } from "electron"; const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); export const startProcessWatcher = async () => { - const sleepTime = 100; + const sleepTime = 300; const gamesPlaytime = new Map(); // eslint-disable-next-line no-constant-condition while (true) { await sleep(sleepTime); - console.time("loopTotalTime"); const games = await gameRepository.find({ where: { executablePath: Not(IsNull()), @@ -26,9 +26,7 @@ export const startProcessWatcher = async () => { continue; } - console.time("getProcesses"); - const processes = await getProcesses(); - console.timeEnd("getProcesses"); + const processes = await getProcesses(app.isPackaged); for (const game of games) { const basename = path.win32.basename(game.executablePath); @@ -73,6 +71,5 @@ export const startProcessWatcher = async () => { } } } - console.timeEnd("loopTotalTime"); } }; From 0bbd7d013fcf3cf0355783196c61be8115470ac2 Mon Sep 17 00:00:00 2001 From: Zamitto Date: Thu, 25 Apr 2024 21:40:46 -0300 Subject: [PATCH 068/140] feat: run fastfile binary from resources folder feat: run process watcher each 300ms feat: add build step to copy fastlist from node_modules feat: create postinstall script to copy fastlist binary remove debug logs --- .gitignore | 3 +++ package.json | 3 ++- postinstall.py | 5 +++++ src/main/events/library/close-game.ts | 3 ++- src/main/helpers/ps.ts | 31 +++++++++++++++++++++++++-- src/main/services/process-watcher.ts | 9 +++----- 6 files changed, 44 insertions(+), 10 deletions(-) create mode 100644 postinstall.py diff --git a/.gitignore b/.gitignore index 0d0363c8..360a16b4 100644 --- a/.gitignore +++ b/.gitignore @@ -106,3 +106,6 @@ resources/dist/ # Sentry Config File .env.sentry-build-plugin + +# Fastlist binary +resources/fastlist.exe diff --git a/package.json b/package.json index 84853898..381dd285 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,8 @@ "make": "electron-forge make", "publish": "electron-forge publish", "lint": "eslint .", - "format": "prettier . --write" + "format": "prettier . --write", + "postinstall": "python3 ./postinstall.py" }, "devDependencies": { "@electron-forge/cli": "^7.3.0", diff --git a/postinstall.py b/postinstall.py new file mode 100644 index 00000000..3fb85d8d --- /dev/null +++ b/postinstall.py @@ -0,0 +1,5 @@ +import shutil +import platform + +if platform.system() == "Windows": + shutil.copy("node_modules/ps-list/vendor/fastlist-0.3.0-x64.exe", "resources/fastlist.exe") diff --git a/src/main/events/library/close-game.ts b/src/main/events/library/close-game.ts index 0d556925..586253b9 100644 --- a/src/main/events/library/close-game.ts +++ b/src/main/events/library/close-game.ts @@ -4,12 +4,13 @@ import { gameRepository } from "@main/repository"; import { registerEvent } from "../register-event"; import { getProcesses } from "@main/helpers"; +import { app } from "electron"; const closeGame = async ( _event: Electron.IpcMainInvokeEvent, gameId: number ) => { - const processes = await getProcesses(); + const processes = await getProcesses(app.isPackaged); const game = await gameRepository.findOne({ where: { id: gameId } }); const gameProcess = processes.find((runningProcess) => { diff --git a/src/main/helpers/ps.ts b/src/main/helpers/ps.ts index 5a30a9ed..449d103f 100644 --- a/src/main/helpers/ps.ts +++ b/src/main/helpers/ps.ts @@ -1,5 +1,32 @@ import psList from "ps-list"; +import path from "node:path"; +import childProcess from "node:child_process"; +import { promisify } from "node:util"; -export const getProcesses = async () => { - return psList(); +const TEN_MEGABYTES = 1000 * 1000 * 10; +const execFile = promisify(childProcess.execFile); + +export const getProcesses = async (isPackaged: boolean) => { + if (process.platform == "win32") { + const binaryPath = isPackaged + ? path.join(process.resourcesPath, "fastlist.exe") + : path.join(__dirname, "..", "..", "resources", "fastlist.exe"); + + const { stdout } = await execFile(binaryPath, { + maxBuffer: TEN_MEGABYTES, + windowsHide: true, + }); + + return stdout + .trim() + .split("\r\n") + .map((line) => line.split("\t")) + .map(([pid, ppid, name]) => ({ + pid: Number.parseInt(pid, 10), + ppid: Number.parseInt(ppid, 10), + name, + })); + } else { + return psList(); + } }; diff --git a/src/main/services/process-watcher.ts b/src/main/services/process-watcher.ts index c040373a..0668c1db 100644 --- a/src/main/services/process-watcher.ts +++ b/src/main/services/process-watcher.ts @@ -4,18 +4,18 @@ import { IsNull, Not } from "typeorm"; import { gameRepository } from "@main/repository"; import { getProcesses } from "@main/helpers"; import { WindowManager } from "./window-manager"; +import { app } from "electron"; const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); export const startProcessWatcher = async () => { - const sleepTime = 100; + const sleepTime = 300; const gamesPlaytime = new Map(); // eslint-disable-next-line no-constant-condition while (true) { await sleep(sleepTime); - console.time("loopTotalTime"); const games = await gameRepository.find({ where: { executablePath: Not(IsNull()), @@ -26,9 +26,7 @@ export const startProcessWatcher = async () => { continue; } - console.time("getProcesses"); - const processes = await getProcesses(); - console.timeEnd("getProcesses"); + const processes = await getProcesses(app.isPackaged); for (const game of games) { const basename = path.win32.basename(game.executablePath); @@ -73,6 +71,5 @@ export const startProcessWatcher = async () => { } } } - console.timeEnd("loopTotalTime"); } }; From 315e06a7b8404b3b9501d0f91dbb525c68c656e8 Mon Sep 17 00:00:00 2001 From: Zamitto <> Date: Fri, 26 Apr 2024 00:12:17 -0300 Subject: [PATCH 069/140] add fastlist.exe to extraResources --- forge.config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/forge.config.ts b/forge.config.ts index 94cfac57..4e6cdb21 100644 --- a/forge.config.ts +++ b/forge.config.ts @@ -30,6 +30,7 @@ const config: ForgeConfig = { executableName: "Hydra", extraResource: [ "./resources/hydra.db", + "./resources/fastlist.exe", "./resources/icon_tray.png", "./resources/dist", ], From fd6ab62e13a584198af6345c5c5b5186b8e7ddfd Mon Sep 17 00:00:00 2001 From: Zamitto <> Date: Fri, 26 Apr 2024 00:12:17 -0300 Subject: [PATCH 070/140] add fastlist.exe to extraResources --- forge.config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/forge.config.ts b/forge.config.ts index 94cfac57..4e6cdb21 100644 --- a/forge.config.ts +++ b/forge.config.ts @@ -30,6 +30,7 @@ const config: ForgeConfig = { executableName: "Hydra", extraResource: [ "./resources/hydra.db", + "./resources/fastlist.exe", "./resources/icon_tray.png", "./resources/dist", ], From 5419376d091aac34fcffc64f09aee78d29cfd6a1 Mon Sep 17 00:00:00 2001 From: Zamitto Date: Fri, 26 Apr 2024 00:22:28 -0300 Subject: [PATCH 071/140] chage fastlis.exe location to not conflict with linux build --- forge.config.ts | 1 - postinstall.py | 6 +++++- src/main/helpers/ps.ts | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/forge.config.ts b/forge.config.ts index 4e6cdb21..94cfac57 100644 --- a/forge.config.ts +++ b/forge.config.ts @@ -30,7 +30,6 @@ const config: ForgeConfig = { executableName: "Hydra", extraResource: [ "./resources/hydra.db", - "./resources/fastlist.exe", "./resources/icon_tray.png", "./resources/dist", ], diff --git a/postinstall.py b/postinstall.py index 3fb85d8d..c55dca60 100644 --- a/postinstall.py +++ b/postinstall.py @@ -1,5 +1,9 @@ import shutil import platform +import os if platform.system() == "Windows": - shutil.copy("node_modules/ps-list/vendor/fastlist-0.3.0-x64.exe", "resources/fastlist.exe") + if not os.path.exists("resources/dist"): + os.mkdir("resources/dist") + + shutil.copy("node_modules/ps-list/vendor/fastlist-0.3.0-x64.exe", "resources/dist/fastlist.exe") diff --git a/src/main/helpers/ps.ts b/src/main/helpers/ps.ts index 449d103f..3d83cc7d 100644 --- a/src/main/helpers/ps.ts +++ b/src/main/helpers/ps.ts @@ -9,8 +9,8 @@ const execFile = promisify(childProcess.execFile); export const getProcesses = async (isPackaged: boolean) => { if (process.platform == "win32") { const binaryPath = isPackaged - ? path.join(process.resourcesPath, "fastlist.exe") - : path.join(__dirname, "..", "..", "resources", "fastlist.exe"); + ? path.join(process.resourcesPath, "dist", "fastlist.exe") + : path.join(__dirname, "..", "..", "resources", "dist", "fastlist.exe"); const { stdout } = await execFile(binaryPath, { maxBuffer: TEN_MEGABYTES, From 7f7d4a1db3ce94636200493d0899dd0830d2dd0f Mon Sep 17 00:00:00 2001 From: Zamitto Date: Fri, 26 Apr 2024 00:22:28 -0300 Subject: [PATCH 072/140] chage fastlis.exe location to not conflict with linux build --- forge.config.ts | 1 - postinstall.py | 6 +++++- src/main/helpers/ps.ts | 4 ++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/forge.config.ts b/forge.config.ts index 4e6cdb21..94cfac57 100644 --- a/forge.config.ts +++ b/forge.config.ts @@ -30,7 +30,6 @@ const config: ForgeConfig = { executableName: "Hydra", extraResource: [ "./resources/hydra.db", - "./resources/fastlist.exe", "./resources/icon_tray.png", "./resources/dist", ], diff --git a/postinstall.py b/postinstall.py index 3fb85d8d..c55dca60 100644 --- a/postinstall.py +++ b/postinstall.py @@ -1,5 +1,9 @@ import shutil import platform +import os if platform.system() == "Windows": - shutil.copy("node_modules/ps-list/vendor/fastlist-0.3.0-x64.exe", "resources/fastlist.exe") + if not os.path.exists("resources/dist"): + os.mkdir("resources/dist") + + shutil.copy("node_modules/ps-list/vendor/fastlist-0.3.0-x64.exe", "resources/dist/fastlist.exe") diff --git a/src/main/helpers/ps.ts b/src/main/helpers/ps.ts index 449d103f..3d83cc7d 100644 --- a/src/main/helpers/ps.ts +++ b/src/main/helpers/ps.ts @@ -9,8 +9,8 @@ const execFile = promisify(childProcess.execFile); export const getProcesses = async (isPackaged: boolean) => { if (process.platform == "win32") { const binaryPath = isPackaged - ? path.join(process.resourcesPath, "fastlist.exe") - : path.join(__dirname, "..", "..", "resources", "fastlist.exe"); + ? path.join(process.resourcesPath, "dist", "fastlist.exe") + : path.join(__dirname, "..", "..", "resources", "dist", "fastlist.exe"); const { stdout } = await execFile(binaryPath, { maxBuffer: TEN_MEGABYTES, From 349acbc779c77c29eb0dcb7defc9f962a600c675 Mon Sep 17 00:00:00 2001 From: Zamitto Date: Fri, 26 Apr 2024 22:39:25 -0300 Subject: [PATCH 073/140] feat: remove unneeded gitignore --- .gitignore | 3 --- 1 file changed, 3 deletions(-) diff --git a/.gitignore b/.gitignore index 360a16b4..0d0363c8 100644 --- a/.gitignore +++ b/.gitignore @@ -106,6 +106,3 @@ resources/dist/ # Sentry Config File .env.sentry-build-plugin - -# Fastlist binary -resources/fastlist.exe From 2363a6d0b29cb17078875d1cf23df59bacba01fd Mon Sep 17 00:00:00 2001 From: Zamitto Date: Fri, 26 Apr 2024 22:39:25 -0300 Subject: [PATCH 074/140] feat: remove unneeded gitignore --- .gitignore | 3 --- 1 file changed, 3 deletions(-) diff --git a/.gitignore b/.gitignore index 360a16b4..0d0363c8 100644 --- a/.gitignore +++ b/.gitignore @@ -106,6 +106,3 @@ resources/dist/ # Sentry Config File .env.sentry-build-plugin - -# Fastlist binary -resources/fastlist.exe From decfe4369cc790a4137041c2bfc557d59a39da56 Mon Sep 17 00:00:00 2001 From: Zamitto Date: Fri, 26 Apr 2024 22:42:07 -0300 Subject: [PATCH 075/140] feat: remove tasklist ts declaration and remove tasklist dependency --- package.json | 1 - src/declaration.d.ts | 13 ------------ yarn.lock | 50 -------------------------------------------- 3 files changed, 64 deletions(-) delete mode 100644 src/declaration.d.ts diff --git a/package.json b/package.json index 381dd285..39029b30 100644 --- a/package.json +++ b/package.json @@ -97,7 +97,6 @@ "react-redux": "^9.1.0", "react-router-dom": "^6.22.3", "sqlite3": "^5.1.7", - "tasklist": "^5.0.0", "tough-cookie": "^4.1.3", "typeorm": "^0.3.20", "update-electron-app": "^3.0.0", diff --git a/src/declaration.d.ts b/src/declaration.d.ts deleted file mode 100644 index 26dfcc27..00000000 --- a/src/declaration.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -declare module "tasklist" { - interface Task { - imageName: string; - pid: number; - sessionName: string; - sessionNumber: number; - memUsage: number; - } - - function tasklist(): Promise; - - export { tasklist }; -} diff --git a/yarn.lock b/yarn.lock index c6450c09..78c336e0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4611,31 +4611,6 @@ csstype@^3.0.2, csstype@^3.0.7: resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz" integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== -csv-generate@^3.4.3: - version "3.4.3" - resolved "https://registry.npmjs.org/csv-generate/-/csv-generate-3.4.3.tgz" - integrity sha512-w/T+rqR0vwvHqWs/1ZyMDWtHHSJaN06klRqJXBEpDJaM/+dZkso0OKh1VcuuYvK3XM53KysVNq8Ko/epCK8wOw== - -csv-parse@^4.16.3: - version "4.16.3" - resolved "https://registry.npmjs.org/csv-parse/-/csv-parse-4.16.3.tgz" - integrity sha512-cO1I/zmz4w2dcKHVvpCr7JVRu8/FymG5OEpmvsZYlccYolPBLoVGKUHgNoc4ZGkFeFlWGEDmMyBM+TTqRdW/wg== - -csv-stringify@^5.6.5: - version "5.6.5" - resolved "https://registry.npmjs.org/csv-stringify/-/csv-stringify-5.6.5.tgz" - integrity sha512-PjiQ659aQ+fUTQqSrd1XEDnOr52jh30RBurfzkscaE2tPaFsDH5wOAHJiw8XAHphRknCwMUE9KRayc4K/NbO8A== - -csv@^5.5.0: - version "5.5.3" - resolved "https://registry.npmjs.org/csv/-/csv-5.5.3.tgz" - integrity sha512-QTaY0XjjhTQOdguARF0lGKm5/mEq9PD9/VhZZegHDIBq2tQwgNpHc3dneD4mGo2iJs+fTKv5Bp0fZ+BRuY3Z0g== - dependencies: - csv-generate "^3.4.3" - csv-parse "^4.16.3" - csv-stringify "^5.6.5" - stream-transform "^2.1.3" - cycle@1.0.x: version "1.0.3" resolved "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz" @@ -7936,11 +7911,6 @@ minizlib@^2.0.0, minizlib@^2.1.1, minizlib@^2.1.2: minipass "^3.0.0" yallist "^4.0.0" -mixme@^0.5.1: - version "0.5.10" - resolved "https://registry.npmjs.org/mixme/-/mixme-0.5.10.tgz" - integrity sha512-5H76ANWinB1H3twpJ6JY8uvAtpmFvHNArpilJAjXRKXSDDLPIMoZArw5SH0q9z+lLs8IrMw7Q2VWpWimFKFT1Q== - mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3: version "0.5.3" resolved "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz" @@ -9463,11 +9433,6 @@ schema-utils@^4.0.0: ajv-formats "^2.1.1" ajv-keywords "^5.1.0" -sec@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/sec/-/sec-2.0.0.tgz" - integrity sha512-uq35HWa7mG6YyojrduMXjF8UhOySEf3X0V1uMpSOBYUF09xAMnJaKNSmWXeE3mN7NfJTpNUkmGa6nIpEBMN8Xw== - select-hose@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz" @@ -9882,13 +9847,6 @@ statuses@2.0.1: resolved "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz" integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== -stream-transform@^2.1.3: - version "2.1.3" - resolved "https://registry.npmjs.org/stream-transform/-/stream-transform-2.1.3.tgz" - integrity sha512-9GHUiM5hMiCi6Y03jD2ARC1ettBXkQBoQAe7nJsPknnI0ow10aXjTnew8QtYQmLjzn974BnmWEAJgCY6ZP1DeQ== - dependencies: - mixme "^0.5.1" - "string-width-cjs@npm:string-width@^4.2.0": version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" @@ -10144,14 +10102,6 @@ tar@^6.0.2, tar@^6.0.5, tar@^6.1.11, tar@^6.1.2: mkdirp "^1.0.3" yallist "^4.0.0" -tasklist@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/tasklist/-/tasklist-5.0.0.tgz" - integrity sha512-qPB4J6pseXRqdxAFT1GhlvDPv4FHxWkXs8QVYQWIqusGwn7UXVKOoYu09DZuYWe1K7T5iusHfSoKrv8k9+RfxA== - dependencies: - csv "^5.5.0" - sec "^2.0.0" - temp-dir@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz" From e15479cd6acdfa957ea731b3450d93e346d12dcb Mon Sep 17 00:00:00 2001 From: Zamitto Date: Fri, 26 Apr 2024 22:42:07 -0300 Subject: [PATCH 076/140] feat: remove tasklist ts declaration and remove tasklist dependency --- package.json | 1 - src/declaration.d.ts | 13 ------------ yarn.lock | 50 -------------------------------------------- 3 files changed, 64 deletions(-) delete mode 100644 src/declaration.d.ts diff --git a/package.json b/package.json index 381dd285..39029b30 100644 --- a/package.json +++ b/package.json @@ -97,7 +97,6 @@ "react-redux": "^9.1.0", "react-router-dom": "^6.22.3", "sqlite3": "^5.1.7", - "tasklist": "^5.0.0", "tough-cookie": "^4.1.3", "typeorm": "^0.3.20", "update-electron-app": "^3.0.0", diff --git a/src/declaration.d.ts b/src/declaration.d.ts deleted file mode 100644 index 26dfcc27..00000000 --- a/src/declaration.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -declare module "tasklist" { - interface Task { - imageName: string; - pid: number; - sessionName: string; - sessionNumber: number; - memUsage: number; - } - - function tasklist(): Promise; - - export { tasklist }; -} diff --git a/yarn.lock b/yarn.lock index c6450c09..78c336e0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4611,31 +4611,6 @@ csstype@^3.0.2, csstype@^3.0.7: resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz" integrity sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw== -csv-generate@^3.4.3: - version "3.4.3" - resolved "https://registry.npmjs.org/csv-generate/-/csv-generate-3.4.3.tgz" - integrity sha512-w/T+rqR0vwvHqWs/1ZyMDWtHHSJaN06klRqJXBEpDJaM/+dZkso0OKh1VcuuYvK3XM53KysVNq8Ko/epCK8wOw== - -csv-parse@^4.16.3: - version "4.16.3" - resolved "https://registry.npmjs.org/csv-parse/-/csv-parse-4.16.3.tgz" - integrity sha512-cO1I/zmz4w2dcKHVvpCr7JVRu8/FymG5OEpmvsZYlccYolPBLoVGKUHgNoc4ZGkFeFlWGEDmMyBM+TTqRdW/wg== - -csv-stringify@^5.6.5: - version "5.6.5" - resolved "https://registry.npmjs.org/csv-stringify/-/csv-stringify-5.6.5.tgz" - integrity sha512-PjiQ659aQ+fUTQqSrd1XEDnOr52jh30RBurfzkscaE2tPaFsDH5wOAHJiw8XAHphRknCwMUE9KRayc4K/NbO8A== - -csv@^5.5.0: - version "5.5.3" - resolved "https://registry.npmjs.org/csv/-/csv-5.5.3.tgz" - integrity sha512-QTaY0XjjhTQOdguARF0lGKm5/mEq9PD9/VhZZegHDIBq2tQwgNpHc3dneD4mGo2iJs+fTKv5Bp0fZ+BRuY3Z0g== - dependencies: - csv-generate "^3.4.3" - csv-parse "^4.16.3" - csv-stringify "^5.6.5" - stream-transform "^2.1.3" - cycle@1.0.x: version "1.0.3" resolved "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz" @@ -7936,11 +7911,6 @@ minizlib@^2.0.0, minizlib@^2.1.1, minizlib@^2.1.2: minipass "^3.0.0" yallist "^4.0.0" -mixme@^0.5.1: - version "0.5.10" - resolved "https://registry.npmjs.org/mixme/-/mixme-0.5.10.tgz" - integrity sha512-5H76ANWinB1H3twpJ6JY8uvAtpmFvHNArpilJAjXRKXSDDLPIMoZArw5SH0q9z+lLs8IrMw7Q2VWpWimFKFT1Q== - mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3: version "0.5.3" resolved "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz" @@ -9463,11 +9433,6 @@ schema-utils@^4.0.0: ajv-formats "^2.1.1" ajv-keywords "^5.1.0" -sec@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/sec/-/sec-2.0.0.tgz" - integrity sha512-uq35HWa7mG6YyojrduMXjF8UhOySEf3X0V1uMpSOBYUF09xAMnJaKNSmWXeE3mN7NfJTpNUkmGa6nIpEBMN8Xw== - select-hose@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz" @@ -9882,13 +9847,6 @@ statuses@2.0.1: resolved "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz" integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== -stream-transform@^2.1.3: - version "2.1.3" - resolved "https://registry.npmjs.org/stream-transform/-/stream-transform-2.1.3.tgz" - integrity sha512-9GHUiM5hMiCi6Y03jD2ARC1ettBXkQBoQAe7nJsPknnI0ow10aXjTnew8QtYQmLjzn974BnmWEAJgCY6ZP1DeQ== - dependencies: - mixme "^0.5.1" - "string-width-cjs@npm:string-width@^4.2.0": version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" @@ -10144,14 +10102,6 @@ tar@^6.0.2, tar@^6.0.5, tar@^6.1.11, tar@^6.1.2: mkdirp "^1.0.3" yallist "^4.0.0" -tasklist@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/tasklist/-/tasklist-5.0.0.tgz" - integrity sha512-qPB4J6pseXRqdxAFT1GhlvDPv4FHxWkXs8QVYQWIqusGwn7UXVKOoYu09DZuYWe1K7T5iusHfSoKrv8k9+RfxA== - dependencies: - csv "^5.5.0" - sec "^2.0.0" - temp-dir@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz" From 41ab9333a4577843d595fc78a10dbd94474a7b43 Mon Sep 17 00:00:00 2001 From: Zamitto Date: Fri, 26 Apr 2024 23:02:21 -0300 Subject: [PATCH 077/140] migrate postinstall from py to js --- .eslintignore | 1 + package.json | 2 +- postinstall.js | 9 +++++++++ postinstall.py | 9 --------- 4 files changed, 11 insertions(+), 10 deletions(-) create mode 100644 .eslintignore create mode 100644 postinstall.js delete mode 100644 postinstall.py diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..0854696d --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +postinstall.js \ No newline at end of file diff --git a/package.json b/package.json index 39029b30..b8396713 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "publish": "electron-forge publish", "lint": "eslint .", "format": "prettier . --write", - "postinstall": "python3 ./postinstall.py" + "postinstall": "node ./postinstall.js" }, "devDependencies": { "@electron-forge/cli": "^7.3.0", diff --git a/postinstall.js b/postinstall.js new file mode 100644 index 00000000..63b6399e --- /dev/null +++ b/postinstall.js @@ -0,0 +1,9 @@ +const fs = require("fs") + +if (process.platform === "win32"){ + if (!fs.existsSync("resources/dist")) { + fs.mkdirSync("resources/dist") + } + + fs.copyFileSync("node_modules/ps-list/vendor/fastlist-0.3.0-x64.exe", "resources/dist/fastlist.exe") +} diff --git a/postinstall.py b/postinstall.py deleted file mode 100644 index c55dca60..00000000 --- a/postinstall.py +++ /dev/null @@ -1,9 +0,0 @@ -import shutil -import platform -import os - -if platform.system() == "Windows": - if not os.path.exists("resources/dist"): - os.mkdir("resources/dist") - - shutil.copy("node_modules/ps-list/vendor/fastlist-0.3.0-x64.exe", "resources/dist/fastlist.exe") From 9b9eabd8011fef3b99b5d6cefdc0524ece053004 Mon Sep 17 00:00:00 2001 From: Zamitto Date: Fri, 26 Apr 2024 23:02:21 -0300 Subject: [PATCH 078/140] migrate postinstall from py to js --- .eslintignore | 1 + package.json | 2 +- postinstall.js | 9 +++++++++ postinstall.py | 9 --------- 4 files changed, 11 insertions(+), 10 deletions(-) create mode 100644 .eslintignore create mode 100644 postinstall.js delete mode 100644 postinstall.py diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..0854696d --- /dev/null +++ b/.eslintignore @@ -0,0 +1 @@ +postinstall.js \ No newline at end of file diff --git a/package.json b/package.json index 39029b30..b8396713 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "publish": "electron-forge publish", "lint": "eslint .", "format": "prettier . --write", - "postinstall": "python3 ./postinstall.py" + "postinstall": "node ./postinstall.js" }, "devDependencies": { "@electron-forge/cli": "^7.3.0", diff --git a/postinstall.js b/postinstall.js new file mode 100644 index 00000000..63b6399e --- /dev/null +++ b/postinstall.js @@ -0,0 +1,9 @@ +const fs = require("fs") + +if (process.platform === "win32"){ + if (!fs.existsSync("resources/dist")) { + fs.mkdirSync("resources/dist") + } + + fs.copyFileSync("node_modules/ps-list/vendor/fastlist-0.3.0-x64.exe", "resources/dist/fastlist.exe") +} diff --git a/postinstall.py b/postinstall.py deleted file mode 100644 index c55dca60..00000000 --- a/postinstall.py +++ /dev/null @@ -1,9 +0,0 @@ -import shutil -import platform -import os - -if platform.system() == "Windows": - if not os.path.exists("resources/dist"): - os.mkdir("resources/dist") - - shutil.copy("node_modules/ps-list/vendor/fastlist-0.3.0-x64.exe", "resources/dist/fastlist.exe") From b781bd919ca351a7f82737178ab81b06ff3cc69e Mon Sep 17 00:00:00 2001 From: Zamitto Date: Fri, 26 Apr 2024 23:02:53 -0300 Subject: [PATCH 079/140] use app.isPackaged directly inside getProcesses function --- src/main/events/library/close-game.ts | 3 +-- src/main/helpers/ps.ts | 5 +++-- src/main/services/process-watcher.ts | 3 +-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main/events/library/close-game.ts b/src/main/events/library/close-game.ts index 586253b9..0d556925 100644 --- a/src/main/events/library/close-game.ts +++ b/src/main/events/library/close-game.ts @@ -4,13 +4,12 @@ import { gameRepository } from "@main/repository"; import { registerEvent } from "../register-event"; import { getProcesses } from "@main/helpers"; -import { app } from "electron"; const closeGame = async ( _event: Electron.IpcMainInvokeEvent, gameId: number ) => { - const processes = await getProcesses(app.isPackaged); + const processes = await getProcesses(); const game = await gameRepository.findOne({ where: { id: gameId } }); const gameProcess = processes.find((runningProcess) => { diff --git a/src/main/helpers/ps.ts b/src/main/helpers/ps.ts index 3d83cc7d..dbc11f09 100644 --- a/src/main/helpers/ps.ts +++ b/src/main/helpers/ps.ts @@ -2,13 +2,14 @@ import psList from "ps-list"; import path from "node:path"; import childProcess from "node:child_process"; import { promisify } from "node:util"; +import { app } from "electron"; const TEN_MEGABYTES = 1000 * 1000 * 10; const execFile = promisify(childProcess.execFile); -export const getProcesses = async (isPackaged: boolean) => { +export const getProcesses = async () => { if (process.platform == "win32") { - const binaryPath = isPackaged + const binaryPath = app.isPackaged ? path.join(process.resourcesPath, "dist", "fastlist.exe") : path.join(__dirname, "..", "..", "resources", "dist", "fastlist.exe"); diff --git a/src/main/services/process-watcher.ts b/src/main/services/process-watcher.ts index 0668c1db..0d699165 100644 --- a/src/main/services/process-watcher.ts +++ b/src/main/services/process-watcher.ts @@ -4,7 +4,6 @@ import { IsNull, Not } from "typeorm"; import { gameRepository } from "@main/repository"; import { getProcesses } from "@main/helpers"; import { WindowManager } from "./window-manager"; -import { app } from "electron"; const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); @@ -26,7 +25,7 @@ export const startProcessWatcher = async () => { continue; } - const processes = await getProcesses(app.isPackaged); + const processes = await getProcesses(); for (const game of games) { const basename = path.win32.basename(game.executablePath); From a4edff36191a80b4503305368540290782879174 Mon Sep 17 00:00:00 2001 From: Zamitto Date: Fri, 26 Apr 2024 23:02:53 -0300 Subject: [PATCH 080/140] use app.isPackaged directly inside getProcesses function --- src/main/events/library/close-game.ts | 3 +-- src/main/helpers/ps.ts | 5 +++-- src/main/services/process-watcher.ts | 3 +-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main/events/library/close-game.ts b/src/main/events/library/close-game.ts index 586253b9..0d556925 100644 --- a/src/main/events/library/close-game.ts +++ b/src/main/events/library/close-game.ts @@ -4,13 +4,12 @@ import { gameRepository } from "@main/repository"; import { registerEvent } from "../register-event"; import { getProcesses } from "@main/helpers"; -import { app } from "electron"; const closeGame = async ( _event: Electron.IpcMainInvokeEvent, gameId: number ) => { - const processes = await getProcesses(app.isPackaged); + const processes = await getProcesses(); const game = await gameRepository.findOne({ where: { id: gameId } }); const gameProcess = processes.find((runningProcess) => { diff --git a/src/main/helpers/ps.ts b/src/main/helpers/ps.ts index 3d83cc7d..dbc11f09 100644 --- a/src/main/helpers/ps.ts +++ b/src/main/helpers/ps.ts @@ -2,13 +2,14 @@ import psList from "ps-list"; import path from "node:path"; import childProcess from "node:child_process"; import { promisify } from "node:util"; +import { app } from "electron"; const TEN_MEGABYTES = 1000 * 1000 * 10; const execFile = promisify(childProcess.execFile); -export const getProcesses = async (isPackaged: boolean) => { +export const getProcesses = async () => { if (process.platform == "win32") { - const binaryPath = isPackaged + const binaryPath = app.isPackaged ? path.join(process.resourcesPath, "dist", "fastlist.exe") : path.join(__dirname, "..", "..", "resources", "dist", "fastlist.exe"); diff --git a/src/main/services/process-watcher.ts b/src/main/services/process-watcher.ts index 0668c1db..0d699165 100644 --- a/src/main/services/process-watcher.ts +++ b/src/main/services/process-watcher.ts @@ -4,7 +4,6 @@ import { IsNull, Not } from "typeorm"; import { gameRepository } from "@main/repository"; import { getProcesses } from "@main/helpers"; import { WindowManager } from "./window-manager"; -import { app } from "electron"; const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); @@ -26,7 +25,7 @@ export const startProcessWatcher = async () => { continue; } - const processes = await getProcesses(app.isPackaged); + const processes = await getProcesses(); for (const game of games) { const basename = path.win32.basename(game.executablePath); From 0e38e7555a4b8ff94c5f2471d6196984e6f70bf4 Mon Sep 17 00:00:00 2001 From: Zamitto Date: Fri, 26 Apr 2024 23:04:57 -0300 Subject: [PATCH 081/140] add new line to .eslintignore --- .eslintignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.eslintignore b/.eslintignore index 0854696d..289e7a42 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1 +1 @@ -postinstall.js \ No newline at end of file +postinstall.js From bcfa3bb795906bb17e1a8529358362a425a629ee Mon Sep 17 00:00:00 2001 From: Zamitto Date: Fri, 26 Apr 2024 23:04:57 -0300 Subject: [PATCH 082/140] add new line to .eslintignore --- .eslintignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.eslintignore b/.eslintignore index 0854696d..289e7a42 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1 +1 @@ -postinstall.js \ No newline at end of file +postinstall.js From d7810eec380ad540d9bb2dc014db5af62279df3d Mon Sep 17 00:00:00 2001 From: Zamitto Date: Sat, 27 Apr 2024 18:40:05 -0300 Subject: [PATCH 083/140] feat: get all games on first request --- src/main/events/catalogue/get-random-game.ts | 39 ++++++++++++++------ src/main/services/steam-250.ts | 13 +++++-- 2 files changed, 37 insertions(+), 15 deletions(-) diff --git a/src/main/events/catalogue/get-random-game.ts b/src/main/events/catalogue/get-random-game.ts index 07a827dd..d4bfd6af 100644 --- a/src/main/events/catalogue/get-random-game.ts +++ b/src/main/events/catalogue/get-random-game.ts @@ -1,27 +1,44 @@ import shuffle from "lodash/shuffle"; -import { getRandomSteam250List } from "@main/services"; +import { Steam250Game, getSteam250List } from "@main/services"; import { registerEvent } from "../register-event"; import { searchGames, searchRepacks } from "../helpers/search-games"; import { formatName } from "@main/helpers"; +let gamesList = new Array(); +let nextGameIndex = 0; + const getRandomGame = async (_event: Electron.IpcMainInvokeEvent) => { - return getRandomSteam250List().then(async (games) => { - const shuffledList = shuffle(games); + if (gamesList.length == 0) { + console.log("fetching steam 250 pages"); + gamesList = shuffle(await getSteam250List()); + } else { + console.log("getting cached list"); + } - for (const game of shuffledList) { - const repacks = searchRepacks(formatName(game.title)); + let resultObjectId = ""; - if (repacks.length) { - const results = await searchGames({ query: game.title }); + while (!resultObjectId) { + const game = gamesList[nextGameIndex]; + const repacks = searchRepacks(formatName(game.title)); - if (results.length) { - return results[0].objectID; - } + if (repacks.length) { + const results = await searchGames({ query: game.title }); + + if (results.length) { + resultObjectId = results[0].objectID; } } - }); + nextGameIndex += 1; + + if (nextGameIndex == gamesList.length - 1) { + nextGameIndex = 0; + gamesList = shuffle(gamesList); + } + } + + return resultObjectId; }; registerEvent(getRandomGame, { diff --git a/src/main/services/steam-250.ts b/src/main/services/steam-250.ts index 6447c226..079f067f 100644 --- a/src/main/services/steam-250.ts +++ b/src/main/services/steam-250.ts @@ -1,6 +1,10 @@ import axios from "axios"; import { JSDOM } from "jsdom"; -import shuffle from "lodash/shuffle"; + +export interface Steam250Game { + title: string; + objectID: string; +} export const requestSteam250 = async (path: string) => { return axios.get(`https://steam250.com${path}`).then((response) => { @@ -28,7 +32,8 @@ const steam250Paths = [ "/most_played", ]; -export const getRandomSteam250List = async () => { - const [path] = shuffle(steam250Paths); - return requestSteam250(path); +export const getSteam250List = async () => { + const gamesPromises = steam250Paths.map((path) => requestSteam250(path)); + const gamesList = (await Promise.all(gamesPromises)).flat(); + return [...new Set(gamesList)]; }; From 6132ddd2b77d37e4a11522038cb4e5aa054ae8bc Mon Sep 17 00:00:00 2001 From: Zamitto Date: Sat, 27 Apr 2024 18:40:05 -0300 Subject: [PATCH 084/140] feat: get all games on first request --- src/main/events/catalogue/get-random-game.ts | 39 ++++++++++++++------ src/main/services/steam-250.ts | 13 +++++-- 2 files changed, 37 insertions(+), 15 deletions(-) diff --git a/src/main/events/catalogue/get-random-game.ts b/src/main/events/catalogue/get-random-game.ts index 07a827dd..d4bfd6af 100644 --- a/src/main/events/catalogue/get-random-game.ts +++ b/src/main/events/catalogue/get-random-game.ts @@ -1,27 +1,44 @@ import shuffle from "lodash/shuffle"; -import { getRandomSteam250List } from "@main/services"; +import { Steam250Game, getSteam250List } from "@main/services"; import { registerEvent } from "../register-event"; import { searchGames, searchRepacks } from "../helpers/search-games"; import { formatName } from "@main/helpers"; +let gamesList = new Array(); +let nextGameIndex = 0; + const getRandomGame = async (_event: Electron.IpcMainInvokeEvent) => { - return getRandomSteam250List().then(async (games) => { - const shuffledList = shuffle(games); + if (gamesList.length == 0) { + console.log("fetching steam 250 pages"); + gamesList = shuffle(await getSteam250List()); + } else { + console.log("getting cached list"); + } - for (const game of shuffledList) { - const repacks = searchRepacks(formatName(game.title)); + let resultObjectId = ""; - if (repacks.length) { - const results = await searchGames({ query: game.title }); + while (!resultObjectId) { + const game = gamesList[nextGameIndex]; + const repacks = searchRepacks(formatName(game.title)); - if (results.length) { - return results[0].objectID; - } + if (repacks.length) { + const results = await searchGames({ query: game.title }); + + if (results.length) { + resultObjectId = results[0].objectID; } } - }); + nextGameIndex += 1; + + if (nextGameIndex == gamesList.length - 1) { + nextGameIndex = 0; + gamesList = shuffle(gamesList); + } + } + + return resultObjectId; }; registerEvent(getRandomGame, { diff --git a/src/main/services/steam-250.ts b/src/main/services/steam-250.ts index 6447c226..079f067f 100644 --- a/src/main/services/steam-250.ts +++ b/src/main/services/steam-250.ts @@ -1,6 +1,10 @@ import axios from "axios"; import { JSDOM } from "jsdom"; -import shuffle from "lodash/shuffle"; + +export interface Steam250Game { + title: string; + objectID: string; +} export const requestSteam250 = async (path: string) => { return axios.get(`https://steam250.com${path}`).then((response) => { @@ -28,7 +32,8 @@ const steam250Paths = [ "/most_played", ]; -export const getRandomSteam250List = async () => { - const [path] = shuffle(steam250Paths); - return requestSteam250(path); +export const getSteam250List = async () => { + const gamesPromises = steam250Paths.map((path) => requestSteam250(path)); + const gamesList = (await Promise.all(gamesPromises)).flat(); + return [...new Set(gamesList)]; }; From 523d711b493e21f0d810924b515056b3610b1050 Mon Sep 17 00:00:00 2001 From: Zamitto Date: Sat, 27 Apr 2024 18:41:37 -0300 Subject: [PATCH 085/140] feat: game-details call getRandomCall on button click --- .../pages/game-details/game-details.tsx | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/renderer/pages/game-details/game-details.tsx b/src/renderer/pages/game-details/game-details.tsx index 7f744198..9015823f 100644 --- a/src/renderer/pages/game-details/game-details.tsx +++ b/src/renderer/pages/game-details/game-details.tsx @@ -53,18 +53,10 @@ export function GameDetails() { const [showRepacksModal, setShowRepacksModal] = useState(false); const [showSelectFolderModal, setShowSelectFolderModal] = useState(false); - const randomGameObjectID = useRef(null); - const dispatch = useAppDispatch(); const { game: gameDownloading, startDownload, isDownloading } = useDownload(); - const getRandomGame = useCallback(() => { - window.electron.getRandomGame().then((objectID) => { - randomGameObjectID.current = objectID; - }); - }, []); - const handleImageSettled = useCallback((url: string) => { average(url, { amount: 1, format: "hex" }) .then((color) => { @@ -89,8 +81,6 @@ export function GameDetails() { setIsGamePlaying(false); dispatch(setHeaderTitle("")); - getRandomGame(); - window.electron .getGameShopDetails(objectID, "steam", getSteamLanguage(i18n.language)) .then((result) => { @@ -114,7 +104,7 @@ export function GameDetails() { getGame(); 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; @@ -158,16 +148,14 @@ export function GameDetails() { }); }; - const handleRandomizerClick = () => { - if (!randomGameObjectID.current) return; + const handleRandomizerClick = async () => { + const randomGameObjectID = await window.electron.getRandomGame(); const searchParams = new URLSearchParams({ fromRandomizer: "1", }); - navigate( - `/game/steam/${randomGameObjectID.current}?${searchParams.toString()}` - ); + navigate(`/game/steam/${randomGameObjectID}?${searchParams.toString()}`); }; const fromRandomizer = searchParams.get("fromRandomizer"); From c9d678be1126862182ba5233fd47ef84d0de940e Mon Sep 17 00:00:00 2001 From: Zamitto Date: Sat, 27 Apr 2024 18:41:37 -0300 Subject: [PATCH 086/140] feat: game-details call getRandomCall on button click --- .../pages/game-details/game-details.tsx | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/src/renderer/pages/game-details/game-details.tsx b/src/renderer/pages/game-details/game-details.tsx index 7f744198..9015823f 100644 --- a/src/renderer/pages/game-details/game-details.tsx +++ b/src/renderer/pages/game-details/game-details.tsx @@ -53,18 +53,10 @@ export function GameDetails() { const [showRepacksModal, setShowRepacksModal] = useState(false); const [showSelectFolderModal, setShowSelectFolderModal] = useState(false); - const randomGameObjectID = useRef(null); - const dispatch = useAppDispatch(); const { game: gameDownloading, startDownload, isDownloading } = useDownload(); - const getRandomGame = useCallback(() => { - window.electron.getRandomGame().then((objectID) => { - randomGameObjectID.current = objectID; - }); - }, []); - const handleImageSettled = useCallback((url: string) => { average(url, { amount: 1, format: "hex" }) .then((color) => { @@ -89,8 +81,6 @@ export function GameDetails() { setIsGamePlaying(false); dispatch(setHeaderTitle("")); - getRandomGame(); - window.electron .getGameShopDetails(objectID, "steam", getSteamLanguage(i18n.language)) .then((result) => { @@ -114,7 +104,7 @@ export function GameDetails() { getGame(); 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; @@ -158,16 +148,14 @@ export function GameDetails() { }); }; - const handleRandomizerClick = () => { - if (!randomGameObjectID.current) return; + const handleRandomizerClick = async () => { + const randomGameObjectID = await window.electron.getRandomGame(); const searchParams = new URLSearchParams({ fromRandomizer: "1", }); - navigate( - `/game/steam/${randomGameObjectID.current}?${searchParams.toString()}` - ); + navigate(`/game/steam/${randomGameObjectID}?${searchParams.toString()}`); }; const fromRandomizer = searchParams.get("fromRandomizer"); From 330dd9c218080b8fc09d70ed9da3ddcd129e448d Mon Sep 17 00:00:00 2001 From: Zamitto Date: Sat, 27 Apr 2024 19:54:37 -0300 Subject: [PATCH 087/140] feat: adjustments --- src/main/events/catalogue/get-random-game.ts | 10 +++++----- src/main/services/steam-250.ts | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/main/events/catalogue/get-random-game.ts b/src/main/events/catalogue/get-random-game.ts index d4bfd6af..c7484d6b 100644 --- a/src/main/events/catalogue/get-random-game.ts +++ b/src/main/events/catalogue/get-random-game.ts @@ -6,7 +6,7 @@ import { registerEvent } from "../register-event"; import { searchGames, searchRepacks } from "../helpers/search-games"; import { formatName } from "@main/helpers"; -let gamesList = new Array(); +let gamesList: Steam250Game[] = []; let nextGameIndex = 0; const getRandomGame = async (_event: Electron.IpcMainInvokeEvent) => { @@ -24,15 +24,15 @@ const getRandomGame = async (_event: Electron.IpcMainInvokeEvent) => { const repacks = searchRepacks(formatName(game.title)); if (repacks.length) { - const results = await searchGames({ query: game.title }); + const catalogueResults = await searchGames({ query: game.title }); - if (results.length) { - resultObjectId = results[0].objectID; + if (catalogueResults.length) { + resultObjectId = catalogueResults[0].objectID; } } nextGameIndex += 1; - if (nextGameIndex == gamesList.length - 1) { + if (nextGameIndex == gamesList.length) { nextGameIndex = 0; gamesList = shuffle(gamesList); } diff --git a/src/main/services/steam-250.ts b/src/main/services/steam-250.ts index 079f067f..dc84cb21 100644 --- a/src/main/services/steam-250.ts +++ b/src/main/services/steam-250.ts @@ -11,17 +11,17 @@ export const requestSteam250 = async (path: string) => { const { window } = new JSDOM(response.data); const { document } = window; - return Array.from(document.querySelectorAll(".appline .title a")).map( - ($title: HTMLAnchorElement) => { + return Array.from(document.querySelectorAll(".appline .title a")) + .map(($title: HTMLAnchorElement) => { const steamGameUrl = $title.href; if (!steamGameUrl) return null; return { title: $title.textContent, objectID: steamGameUrl.split("/").pop(), - }; - } - ); + } as Steam250Game; + }) + .filter((game) => game != null); }); }; From 170a58d3cd40b50660726305a4346c170599be7d Mon Sep 17 00:00:00 2001 From: Zamitto Date: Sat, 27 Apr 2024 19:54:37 -0300 Subject: [PATCH 088/140] feat: adjustments --- src/main/events/catalogue/get-random-game.ts | 10 +++++----- src/main/services/steam-250.ts | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/main/events/catalogue/get-random-game.ts b/src/main/events/catalogue/get-random-game.ts index d4bfd6af..c7484d6b 100644 --- a/src/main/events/catalogue/get-random-game.ts +++ b/src/main/events/catalogue/get-random-game.ts @@ -6,7 +6,7 @@ import { registerEvent } from "../register-event"; import { searchGames, searchRepacks } from "../helpers/search-games"; import { formatName } from "@main/helpers"; -let gamesList = new Array(); +let gamesList: Steam250Game[] = []; let nextGameIndex = 0; const getRandomGame = async (_event: Electron.IpcMainInvokeEvent) => { @@ -24,15 +24,15 @@ const getRandomGame = async (_event: Electron.IpcMainInvokeEvent) => { const repacks = searchRepacks(formatName(game.title)); if (repacks.length) { - const results = await searchGames({ query: game.title }); + const catalogueResults = await searchGames({ query: game.title }); - if (results.length) { - resultObjectId = results[0].objectID; + if (catalogueResults.length) { + resultObjectId = catalogueResults[0].objectID; } } nextGameIndex += 1; - if (nextGameIndex == gamesList.length - 1) { + if (nextGameIndex == gamesList.length) { nextGameIndex = 0; gamesList = shuffle(gamesList); } diff --git a/src/main/services/steam-250.ts b/src/main/services/steam-250.ts index 079f067f..dc84cb21 100644 --- a/src/main/services/steam-250.ts +++ b/src/main/services/steam-250.ts @@ -11,17 +11,17 @@ export const requestSteam250 = async (path: string) => { const { window } = new JSDOM(response.data); const { document } = window; - return Array.from(document.querySelectorAll(".appline .title a")).map( - ($title: HTMLAnchorElement) => { + return Array.from(document.querySelectorAll(".appline .title a")) + .map(($title: HTMLAnchorElement) => { const steamGameUrl = $title.href; if (!steamGameUrl) return null; return { title: $title.textContent, objectID: steamGameUrl.split("/").pop(), - }; - } - ); + } as Steam250Game; + }) + .filter((game) => game != null); }); }; From 6328497372f882aec61eaf3fead4ac588bdf34e9 Mon Sep 17 00:00:00 2001 From: Zamitto Date: Sat, 27 Apr 2024 20:15:24 -0300 Subject: [PATCH 089/140] fix: possible bug when catalogue returns games with similar name --- src/main/events/catalogue/get-random-game.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/events/catalogue/get-random-game.ts b/src/main/events/catalogue/get-random-game.ts index c7484d6b..fc7cb5db 100644 --- a/src/main/events/catalogue/get-random-game.ts +++ b/src/main/events/catalogue/get-random-game.ts @@ -27,7 +27,7 @@ const getRandomGame = async (_event: Electron.IpcMainInvokeEvent) => { const catalogueResults = await searchGames({ query: game.title }); if (catalogueResults.length) { - resultObjectId = catalogueResults[0].objectID; + resultObjectId = game.objectID; } } nextGameIndex += 1; From 5d8813a78f163f52eab44ec4ac850b759462fbf2 Mon Sep 17 00:00:00 2001 From: Zamitto Date: Sat, 27 Apr 2024 20:15:24 -0300 Subject: [PATCH 090/140] fix: possible bug when catalogue returns games with similar name --- src/main/events/catalogue/get-random-game.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/events/catalogue/get-random-game.ts b/src/main/events/catalogue/get-random-game.ts index c7484d6b..fc7cb5db 100644 --- a/src/main/events/catalogue/get-random-game.ts +++ b/src/main/events/catalogue/get-random-game.ts @@ -27,7 +27,7 @@ const getRandomGame = async (_event: Electron.IpcMainInvokeEvent) => { const catalogueResults = await searchGames({ query: game.title }); if (catalogueResults.length) { - resultObjectId = catalogueResults[0].objectID; + resultObjectId = game.objectID; } } nextGameIndex += 1; From 135c9be5f72abd2f30add61a6ceeeecae5513abe Mon Sep 17 00:00:00 2001 From: Zamitto Date: Sat, 27 Apr 2024 20:42:28 -0300 Subject: [PATCH 091/140] replace Set with Map --- src/main/services/steam-250.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/services/steam-250.ts b/src/main/services/steam-250.ts index dc84cb21..cec70774 100644 --- a/src/main/services/steam-250.ts +++ b/src/main/services/steam-250.ts @@ -35,5 +35,11 @@ const steam250Paths = [ export const getSteam250List = async () => { const gamesPromises = steam250Paths.map((path) => requestSteam250(path)); const gamesList = (await Promise.all(gamesPromises)).flat(); - return [...new Set(gamesList)]; + + const gamesMap = gamesList.reduce((map, item) => { + map.set(item.objectID, item); + return map; + }, new Map()); + + return [...gamesMap.values()]; }; From 74a5d5c7f4941af2ea92e4e674050f0149bce4f9 Mon Sep 17 00:00:00 2001 From: Zamitto Date: Sat, 27 Apr 2024 20:42:28 -0300 Subject: [PATCH 092/140] replace Set with Map --- src/main/services/steam-250.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/services/steam-250.ts b/src/main/services/steam-250.ts index dc84cb21..cec70774 100644 --- a/src/main/services/steam-250.ts +++ b/src/main/services/steam-250.ts @@ -35,5 +35,11 @@ const steam250Paths = [ export const getSteam250List = async () => { const gamesPromises = steam250Paths.map((path) => requestSteam250(path)); const gamesList = (await Promise.all(gamesPromises)).flat(); - return [...new Set(gamesList)]; + + const gamesMap = gamesList.reduce((map, item) => { + map.set(item.objectID, item); + return map; + }, new Map()); + + return [...gamesMap.values()]; }; From 588dc5bb54694257da3c562064f3eaeae16ebcc2 Mon Sep 17 00:00:00 2001 From: Zamitto Date: Sat, 27 Apr 2024 20:42:50 -0300 Subject: [PATCH 093/140] renaming variables --- src/main/events/catalogue/get-random-game.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/events/catalogue/get-random-game.ts b/src/main/events/catalogue/get-random-game.ts index fc7cb5db..d3f82590 100644 --- a/src/main/events/catalogue/get-random-game.ts +++ b/src/main/events/catalogue/get-random-game.ts @@ -20,14 +20,13 @@ const getRandomGame = async (_event: Electron.IpcMainInvokeEvent) => { let resultObjectId = ""; while (!resultObjectId) { - const game = gamesList[nextGameIndex]; - const repacks = searchRepacks(formatName(game.title)); + const nextGame = gamesList[nextGameIndex]; + const repacks = searchRepacks(formatName(nextGame.title)); if (repacks.length) { - const catalogueResults = await searchGames({ query: game.title }); - + const catalogueResults = await searchGames({ query: nextGame.title }); if (catalogueResults.length) { - resultObjectId = game.objectID; + resultObjectId = nextGame.objectID; } } nextGameIndex += 1; From 2904302c81ab44d6ed31214f1f9d18dbb440127b Mon Sep 17 00:00:00 2001 From: Zamitto Date: Sat, 27 Apr 2024 20:42:50 -0300 Subject: [PATCH 094/140] renaming variables --- src/main/events/catalogue/get-random-game.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/events/catalogue/get-random-game.ts b/src/main/events/catalogue/get-random-game.ts index fc7cb5db..d3f82590 100644 --- a/src/main/events/catalogue/get-random-game.ts +++ b/src/main/events/catalogue/get-random-game.ts @@ -20,14 +20,13 @@ const getRandomGame = async (_event: Electron.IpcMainInvokeEvent) => { let resultObjectId = ""; while (!resultObjectId) { - const game = gamesList[nextGameIndex]; - const repacks = searchRepacks(formatName(game.title)); + const nextGame = gamesList[nextGameIndex]; + const repacks = searchRepacks(formatName(nextGame.title)); if (repacks.length) { - const catalogueResults = await searchGames({ query: game.title }); - + const catalogueResults = await searchGames({ query: nextGame.title }); if (catalogueResults.length) { - resultObjectId = game.objectID; + resultObjectId = nextGame.objectID; } } nextGameIndex += 1; From 2839d65526301e2fb361583686da185aeaa2c0f7 Mon Sep 17 00:00:00 2001 From: Zamitto Date: Sat, 27 Apr 2024 20:43:34 -0300 Subject: [PATCH 095/140] fix possibility of 404 on home if getRandomGame has no validy elements to return this can happen when user has no internet connection when opening hydra --- src/main/services/steam-250.ts | 31 +++++++++++++++++-------------- src/renderer/pages/home/home.tsx | 10 ++++------ 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/main/services/steam-250.ts b/src/main/services/steam-250.ts index cec70774..28c27046 100644 --- a/src/main/services/steam-250.ts +++ b/src/main/services/steam-250.ts @@ -7,22 +7,25 @@ export interface Steam250Game { } export const requestSteam250 = async (path: string) => { - return axios.get(`https://steam250.com${path}`).then((response) => { - const { window } = new JSDOM(response.data); - const { document } = window; + return axios + .get(`https://steam250.com${path}`) + .then((response) => { + const { window } = new JSDOM(response.data); + const { document } = window; - return Array.from(document.querySelectorAll(".appline .title a")) - .map(($title: HTMLAnchorElement) => { - const steamGameUrl = $title.href; - if (!steamGameUrl) return null; + return Array.from(document.querySelectorAll(".appline .title a")) + .map(($title: HTMLAnchorElement) => { + const steamGameUrl = $title.href; + if (!steamGameUrl) return null; - return { - title: $title.textContent, - objectID: steamGameUrl.split("/").pop(), - } as Steam250Game; - }) - .filter((game) => game != null); - }); + return { + title: $title.textContent, + objectID: steamGameUrl.split("/").pop(), + } as Steam250Game; + }) + .filter((game) => game != null); + }) + .catch((_) => []); }; const steam250Paths = [ diff --git a/src/renderer/pages/home/home.tsx b/src/renderer/pages/home/home.tsx index ed650245..33811483 100644 --- a/src/renderer/pages/home/home.tsx +++ b/src/renderer/pages/home/home.tsx @@ -58,14 +58,12 @@ export function Home() { const getRandomGame = useCallback(() => { setIsLoadingRandomGame(true); - window.electron - .getRandomGame() - .then((objectID) => { + window.electron.getRandomGame().then((objectID) => { + if (objectID) { randomGameObjectID.current = objectID; - }) - .finally(() => { setIsLoadingRandomGame(false); - }); + } + }); }, []); const handleRandomizerClick = () => { From a8b236e02cce3065c1c75c3018f77506b8f4d342 Mon Sep 17 00:00:00 2001 From: Zamitto Date: Sat, 27 Apr 2024 20:43:34 -0300 Subject: [PATCH 096/140] fix possibility of 404 on home if getRandomGame has no validy elements to return this can happen when user has no internet connection when opening hydra --- src/main/services/steam-250.ts | 31 +++++++++++++++++-------------- src/renderer/pages/home/home.tsx | 10 ++++------ 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/src/main/services/steam-250.ts b/src/main/services/steam-250.ts index cec70774..28c27046 100644 --- a/src/main/services/steam-250.ts +++ b/src/main/services/steam-250.ts @@ -7,22 +7,25 @@ export interface Steam250Game { } export const requestSteam250 = async (path: string) => { - return axios.get(`https://steam250.com${path}`).then((response) => { - const { window } = new JSDOM(response.data); - const { document } = window; + return axios + .get(`https://steam250.com${path}`) + .then((response) => { + const { window } = new JSDOM(response.data); + const { document } = window; - return Array.from(document.querySelectorAll(".appline .title a")) - .map(($title: HTMLAnchorElement) => { - const steamGameUrl = $title.href; - if (!steamGameUrl) return null; + return Array.from(document.querySelectorAll(".appline .title a")) + .map(($title: HTMLAnchorElement) => { + const steamGameUrl = $title.href; + if (!steamGameUrl) return null; - return { - title: $title.textContent, - objectID: steamGameUrl.split("/").pop(), - } as Steam250Game; - }) - .filter((game) => game != null); - }); + return { + title: $title.textContent, + objectID: steamGameUrl.split("/").pop(), + } as Steam250Game; + }) + .filter((game) => game != null); + }) + .catch((_) => []); }; const steam250Paths = [ diff --git a/src/renderer/pages/home/home.tsx b/src/renderer/pages/home/home.tsx index ed650245..33811483 100644 --- a/src/renderer/pages/home/home.tsx +++ b/src/renderer/pages/home/home.tsx @@ -58,14 +58,12 @@ export function Home() { const getRandomGame = useCallback(() => { setIsLoadingRandomGame(true); - window.electron - .getRandomGame() - .then((objectID) => { + window.electron.getRandomGame().then((objectID) => { + if (objectID) { randomGameObjectID.current = objectID; - }) - .finally(() => { setIsLoadingRandomGame(false); - }); + } + }); }, []); const handleRandomizerClick = () => { From f9fe68e55031661a62ba558f8c8275242a2fef08 Mon Sep 17 00:00:00 2001 From: Zamitto Date: Sat, 27 Apr 2024 21:00:57 -0300 Subject: [PATCH 097/140] feat: disable next random suggestion button until game details finish loading --- src/renderer/pages/game-details/game-details.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/renderer/pages/game-details/game-details.tsx b/src/renderer/pages/game-details/game-details.tsx index 9015823f..2dc44418 100644 --- a/src/renderer/pages/game-details/game-details.tsx +++ b/src/renderer/pages/game-details/game-details.tsx @@ -33,6 +33,7 @@ export function GameDetails() { const { objectID, shop } = useParams(); const [isLoading, setIsLoading] = useState(false); + const [isLoadingRandomGame, setIsLoadingRandomGame] = useState(false); const [color, setColor] = useState(""); const [gameDetails, setGameDetails] = useState(null); const [howLongToBeat, setHowLongToBeat] = useState<{ @@ -97,6 +98,7 @@ export function GameDetails() { setGameDetails(result); dispatch(setHeaderTitle(result.name)); + setIsLoadingRandomGame(false); }) .finally(() => { setIsLoading(false); @@ -149,6 +151,7 @@ export function GameDetails() { }; const handleRandomizerClick = async () => { + setIsLoadingRandomGame(true); const randomGameObjectID = await window.electron.getRandomGame(); const searchParams = new URLSearchParams({ @@ -269,6 +272,7 @@ export function GameDetails() { className={styles.randomizerButton} onClick={handleRandomizerClick} theme="outline" + disabled={isLoadingRandomGame} >
Date: Sat, 27 Apr 2024 21:00:57 -0300 Subject: [PATCH 098/140] feat: disable next random suggestion button until game details finish loading --- src/renderer/pages/game-details/game-details.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/renderer/pages/game-details/game-details.tsx b/src/renderer/pages/game-details/game-details.tsx index 9015823f..2dc44418 100644 --- a/src/renderer/pages/game-details/game-details.tsx +++ b/src/renderer/pages/game-details/game-details.tsx @@ -33,6 +33,7 @@ export function GameDetails() { const { objectID, shop } = useParams(); const [isLoading, setIsLoading] = useState(false); + const [isLoadingRandomGame, setIsLoadingRandomGame] = useState(false); const [color, setColor] = useState(""); const [gameDetails, setGameDetails] = useState(null); const [howLongToBeat, setHowLongToBeat] = useState<{ @@ -97,6 +98,7 @@ export function GameDetails() { setGameDetails(result); dispatch(setHeaderTitle(result.name)); + setIsLoadingRandomGame(false); }) .finally(() => { setIsLoading(false); @@ -149,6 +151,7 @@ export function GameDetails() { }; const handleRandomizerClick = async () => { + setIsLoadingRandomGame(true); const randomGameObjectID = await window.electron.getRandomGame(); const searchParams = new URLSearchParams({ @@ -269,6 +272,7 @@ export function GameDetails() { className={styles.randomizerButton} onClick={handleRandomizerClick} theme="outline" + disabled={isLoadingRandomGame} >
Date: Sat, 27 Apr 2024 22:04:35 -0300 Subject: [PATCH 099/140] removing async from searchGames --- src/main/events/helpers/search-games.ts | 15 +++++++-------- src/main/services/steam-250.ts | 4 ++-- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/main/events/helpers/search-games.ts b/src/main/events/helpers/search-games.ts index 5fb3cea0..6d6f1ded 100644 --- a/src/main/events/helpers/search-games.ts +++ b/src/main/events/helpers/search-games.ts @@ -42,11 +42,12 @@ export interface SearchGamesArgs { skip?: number; } -export const searchGames = async ({ +// Check if this function really needed to be an async function +export const searchGames = ({ query, take, skip, -}: SearchGamesArgs): Promise => { +}: SearchGamesArgs): CatalogueEntry[] => { const results = steamGamesIndex .search(formatName(query || ""), { limit: take, offset: skip }) .map((index) => { @@ -61,11 +62,9 @@ export const searchGames = async ({ }; }); - return Promise.all(results).then((resultsWithRepacks) => - orderBy( - resultsWithRepacks, - [({ repacks }) => repacks.length, "repacks"], - ["desc"] - ) + return orderBy( + results, + [({ repacks }) => repacks.length, "repacks"], + ["desc"] ); }; diff --git a/src/main/services/steam-250.ts b/src/main/services/steam-250.ts index 28c27046..f0aee3bf 100644 --- a/src/main/services/steam-250.ts +++ b/src/main/services/steam-250.ts @@ -39,10 +39,10 @@ export const getSteam250List = async () => { const gamesPromises = steam250Paths.map((path) => requestSteam250(path)); const gamesList = (await Promise.all(gamesPromises)).flat(); - const gamesMap = gamesList.reduce((map, item) => { + const gamesMap: Map = gamesList.reduce((map, item) => { map.set(item.objectID, item); return map; - }, new Map()); + }, new Map()); return [...gamesMap.values()]; }; From c32d75713c7f95fcbae16df12b161afd4bcc699c Mon Sep 17 00:00:00 2001 From: Zamitto Date: Sat, 27 Apr 2024 22:04:35 -0300 Subject: [PATCH 100/140] removing async from searchGames --- src/main/events/helpers/search-games.ts | 15 +++++++-------- src/main/services/steam-250.ts | 4 ++-- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/main/events/helpers/search-games.ts b/src/main/events/helpers/search-games.ts index 5fb3cea0..6d6f1ded 100644 --- a/src/main/events/helpers/search-games.ts +++ b/src/main/events/helpers/search-games.ts @@ -42,11 +42,12 @@ export interface SearchGamesArgs { skip?: number; } -export const searchGames = async ({ +// Check if this function really needed to be an async function +export const searchGames = ({ query, take, skip, -}: SearchGamesArgs): Promise => { +}: SearchGamesArgs): CatalogueEntry[] => { const results = steamGamesIndex .search(formatName(query || ""), { limit: take, offset: skip }) .map((index) => { @@ -61,11 +62,9 @@ export const searchGames = async ({ }; }); - return Promise.all(results).then((resultsWithRepacks) => - orderBy( - resultsWithRepacks, - [({ repacks }) => repacks.length, "repacks"], - ["desc"] - ) + return orderBy( + results, + [({ repacks }) => repacks.length, "repacks"], + ["desc"] ); }; diff --git a/src/main/services/steam-250.ts b/src/main/services/steam-250.ts index 28c27046..f0aee3bf 100644 --- a/src/main/services/steam-250.ts +++ b/src/main/services/steam-250.ts @@ -39,10 +39,10 @@ export const getSteam250List = async () => { const gamesPromises = steam250Paths.map((path) => requestSteam250(path)); const gamesList = (await Promise.all(gamesPromises)).flat(); - const gamesMap = gamesList.reduce((map, item) => { + const gamesMap: Map = gamesList.reduce((map, item) => { map.set(item.objectID, item); return map; - }, new Map()); + }, new Map()); return [...gamesMap.values()]; }; From 49d9e5e8c0c8d82db07cd574a8059a3623ecf8fb Mon Sep 17 00:00:00 2001 From: Zamitto Date: Sat, 27 Apr 2024 22:04:42 -0300 Subject: [PATCH 101/140] refactor get-random-game --- src/main/events/catalogue/get-random-game.ts | 38 ++++++++++---------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/src/main/events/catalogue/get-random-game.ts b/src/main/events/catalogue/get-random-game.ts index d3f82590..82a7966b 100644 --- a/src/main/events/catalogue/get-random-game.ts +++ b/src/main/events/catalogue/get-random-game.ts @@ -4,37 +4,35 @@ import { Steam250Game, getSteam250List } from "@main/services"; import { registerEvent } from "../register-event"; import { searchGames, searchRepacks } from "../helpers/search-games"; -import { formatName } from "@main/helpers"; let gamesList: Steam250Game[] = []; let nextGameIndex = 0; const getRandomGame = async (_event: Electron.IpcMainInvokeEvent) => { if (gamesList.length == 0) { - console.log("fetching steam 250 pages"); - gamesList = shuffle(await getSteam250List()); - } else { - console.log("getting cached list"); + const steam250List = await getSteam250List(); + + const filteredSteam250List = steam250List.filter((game) => { + const repacks = searchRepacks(game.title); + const catalogue = searchGames({ query: game.title }); + + return repacks.length && catalogue.length; + }); + + gamesList = shuffle(filteredSteam250List); } - let resultObjectId = ""; + if (gamesList.length == 0) { + return ""; + } - while (!resultObjectId) { - const nextGame = gamesList[nextGameIndex]; - const repacks = searchRepacks(formatName(nextGame.title)); + const resultObjectId = gamesList[nextGameIndex].objectID; - if (repacks.length) { - const catalogueResults = await searchGames({ query: nextGame.title }); - if (catalogueResults.length) { - resultObjectId = nextGame.objectID; - } - } - nextGameIndex += 1; + nextGameIndex += 1; - if (nextGameIndex == gamesList.length) { - nextGameIndex = 0; - gamesList = shuffle(gamesList); - } + if (nextGameIndex == gamesList.length) { + nextGameIndex = 0; + gamesList = shuffle(gamesList); } return resultObjectId; From 4ffaa510ccd233425108a1d121cbf176864b02d8 Mon Sep 17 00:00:00 2001 From: Zamitto Date: Sat, 27 Apr 2024 22:04:42 -0300 Subject: [PATCH 102/140] refactor get-random-game --- src/main/events/catalogue/get-random-game.ts | 38 ++++++++++---------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/src/main/events/catalogue/get-random-game.ts b/src/main/events/catalogue/get-random-game.ts index d3f82590..82a7966b 100644 --- a/src/main/events/catalogue/get-random-game.ts +++ b/src/main/events/catalogue/get-random-game.ts @@ -4,37 +4,35 @@ import { Steam250Game, getSteam250List } from "@main/services"; import { registerEvent } from "../register-event"; import { searchGames, searchRepacks } from "../helpers/search-games"; -import { formatName } from "@main/helpers"; let gamesList: Steam250Game[] = []; let nextGameIndex = 0; const getRandomGame = async (_event: Electron.IpcMainInvokeEvent) => { if (gamesList.length == 0) { - console.log("fetching steam 250 pages"); - gamesList = shuffle(await getSteam250List()); - } else { - console.log("getting cached list"); + const steam250List = await getSteam250List(); + + const filteredSteam250List = steam250List.filter((game) => { + const repacks = searchRepacks(game.title); + const catalogue = searchGames({ query: game.title }); + + return repacks.length && catalogue.length; + }); + + gamesList = shuffle(filteredSteam250List); } - let resultObjectId = ""; + if (gamesList.length == 0) { + return ""; + } - while (!resultObjectId) { - const nextGame = gamesList[nextGameIndex]; - const repacks = searchRepacks(formatName(nextGame.title)); + const resultObjectId = gamesList[nextGameIndex].objectID; - if (repacks.length) { - const catalogueResults = await searchGames({ query: nextGame.title }); - if (catalogueResults.length) { - resultObjectId = nextGame.objectID; - } - } - nextGameIndex += 1; + nextGameIndex += 1; - if (nextGameIndex == gamesList.length) { - nextGameIndex = 0; - gamesList = shuffle(gamesList); - } + if (nextGameIndex == gamesList.length) { + nextGameIndex = 0; + gamesList = shuffle(gamesList); } return resultObjectId; From 1c6ffc8ce2887bbfdccdc1a2aa70f0a6278baa35 Mon Sep 17 00:00:00 2001 From: Zamitto Date: Sun, 28 Apr 2024 00:13:29 -0300 Subject: [PATCH 103/140] make sure the registed event for seachGames returns a Promise --- src/main/events/catalogue/search-games.ts | 20 ++++++++++++-------- src/main/events/helpers/search-games.ts | 1 - src/main/services/steam-250.ts | 2 +- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/main/events/catalogue/search-games.ts b/src/main/events/catalogue/search-games.ts index eb9c0640..cdb84d56 100644 --- a/src/main/events/catalogue/search-games.ts +++ b/src/main/events/catalogue/search-games.ts @@ -1,11 +1,15 @@ import { registerEvent } from "../register-event"; import { searchGames } from "../helpers/search-games"; +import { CatalogueEntry } from "@types"; -registerEvent( - (_event: Electron.IpcMainInvokeEvent, query: string) => - searchGames({ query, take: 12 }), - { - name: "searchGames", - memoize: true, - } -); +const searchGamesEvent = async ( + _event: Electron.IpcMainInvokeEvent, + query: string +): Promise => { + return Promise.all(searchGames({ query, take: 12 })); +}; + +registerEvent(searchGamesEvent, { + name: "searchGames", + memoize: true, +}); diff --git a/src/main/events/helpers/search-games.ts b/src/main/events/helpers/search-games.ts index 6d6f1ded..50777dd7 100644 --- a/src/main/events/helpers/search-games.ts +++ b/src/main/events/helpers/search-games.ts @@ -42,7 +42,6 @@ export interface SearchGamesArgs { skip?: number; } -// Check if this function really needed to be an async function export const searchGames = ({ query, take, diff --git a/src/main/services/steam-250.ts b/src/main/services/steam-250.ts index f0aee3bf..f5c92364 100644 --- a/src/main/services/steam-250.ts +++ b/src/main/services/steam-250.ts @@ -25,7 +25,7 @@ export const requestSteam250 = async (path: string) => { }) .filter((game) => game != null); }) - .catch((_) => []); + .catch((_) => [] as Steam250Game[]); }; const steam250Paths = [ From bb9302908d070cb3cd2f79db79fc07039d8d10f9 Mon Sep 17 00:00:00 2001 From: Zamitto Date: Sun, 28 Apr 2024 00:13:29 -0300 Subject: [PATCH 104/140] make sure the registed event for seachGames returns a Promise --- src/main/events/catalogue/search-games.ts | 20 ++++++++++++-------- src/main/events/helpers/search-games.ts | 1 - src/main/services/steam-250.ts | 2 +- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/main/events/catalogue/search-games.ts b/src/main/events/catalogue/search-games.ts index eb9c0640..cdb84d56 100644 --- a/src/main/events/catalogue/search-games.ts +++ b/src/main/events/catalogue/search-games.ts @@ -1,11 +1,15 @@ import { registerEvent } from "../register-event"; import { searchGames } from "../helpers/search-games"; +import { CatalogueEntry } from "@types"; -registerEvent( - (_event: Electron.IpcMainInvokeEvent, query: string) => - searchGames({ query, take: 12 }), - { - name: "searchGames", - memoize: true, - } -); +const searchGamesEvent = async ( + _event: Electron.IpcMainInvokeEvent, + query: string +): Promise => { + return Promise.all(searchGames({ query, take: 12 })); +}; + +registerEvent(searchGamesEvent, { + name: "searchGames", + memoize: true, +}); diff --git a/src/main/events/helpers/search-games.ts b/src/main/events/helpers/search-games.ts index 6d6f1ded..50777dd7 100644 --- a/src/main/events/helpers/search-games.ts +++ b/src/main/events/helpers/search-games.ts @@ -42,7 +42,6 @@ export interface SearchGamesArgs { skip?: number; } -// Check if this function really needed to be an async function export const searchGames = ({ query, take, diff --git a/src/main/services/steam-250.ts b/src/main/services/steam-250.ts index f0aee3bf..f5c92364 100644 --- a/src/main/services/steam-250.ts +++ b/src/main/services/steam-250.ts @@ -25,7 +25,7 @@ export const requestSteam250 = async (path: string) => { }) .filter((game) => game != null); }) - .catch((_) => []); + .catch((_) => [] as Steam250Game[]); }; const steam250Paths = [ From 9c330c40a8d9a5dbf08cc77b093a673c08b09e19 Mon Sep 17 00:00:00 2001 From: Zamitto Date: Sun, 28 Apr 2024 00:28:12 -0300 Subject: [PATCH 105/140] remove unused import and fix lint --- src/renderer/pages/game-details/game-details.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/pages/game-details/game-details.tsx b/src/renderer/pages/game-details/game-details.tsx index 2dc44418..41ba215e 100644 --- a/src/renderer/pages/game-details/game-details.tsx +++ b/src/renderer/pages/game-details/game-details.tsx @@ -1,6 +1,6 @@ import Color from "color"; 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 type { From 632cd244b02a51bfe3e988164e09100637b2bf04 Mon Sep 17 00:00:00 2001 From: Zamitto Date: Sun, 28 Apr 2024 00:28:12 -0300 Subject: [PATCH 106/140] remove unused import and fix lint --- src/renderer/pages/game-details/game-details.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/pages/game-details/game-details.tsx b/src/renderer/pages/game-details/game-details.tsx index 2dc44418..41ba215e 100644 --- a/src/renderer/pages/game-details/game-details.tsx +++ b/src/renderer/pages/game-details/game-details.tsx @@ -1,6 +1,6 @@ import Color from "color"; 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 type { From 842dc22f3dc952550eebacda383e33023ccac097 Mon Sep 17 00:00:00 2001 From: Hydra Date: Sun, 28 Apr 2024 05:59:06 +0100 Subject: [PATCH 107/140] feat: adding tray icon --- .gitignore | 3 + electron.vite.config.ts | 27 +++- package.json | 1 + resources/tray-icon.png | Bin 0 -> 178866 bytes src/main/services/window-manager.ts | 2 +- yarn.lock | 222 ++++++++++++++++++++++++++-- 6 files changed, 241 insertions(+), 14 deletions(-) create mode 100644 resources/tray-icon.png diff --git a/.gitignore b/.gitignore index 3cb8d1ca..0767dd62 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,6 @@ out *.log* .env .vite + +# Sentry Config File +.env.sentry-build-plugin diff --git a/electron.vite.config.ts b/electron.vite.config.ts index d3265042..3bb8eb01 100644 --- a/electron.vite.config.ts +++ b/electron.vite.config.ts @@ -8,14 +8,21 @@ import { } from "electron-vite"; import react from "@vitejs/plugin-react"; import { vanillaExtractPlugin } from "@vanilla-extract/vite-plugin"; +import { sentryVitePlugin } from "@sentry/vite-plugin"; import svgr from "vite-plugin-svgr"; - export default defineConfig(({ mode }) => { loadEnv(mode); + const sentryPlugin = sentryVitePlugin({ + authToken: process.env.SENTRY_AUTH_TOKEN, + org: "hydra-launcher", + project: "hydra-launcher", + }); + return { main: { build: { + sourcemap: true, rollupOptions: { external: ["better-sqlite3"], }, @@ -26,19 +33,33 @@ export default defineConfig(({ mode }) => { "@locales": resolve("src/locales"), }, }, - plugins: [externalizeDepsPlugin(), swcPlugin(), bytecodePlugin()], + plugins: [ + externalizeDepsPlugin(), + swcPlugin(), + bytecodePlugin(), + sentryPlugin, + ], }, preload: { plugins: [externalizeDepsPlugin()], }, renderer: { + build: { + sourcemap: true, + }, resolve: { alias: { "@renderer": resolve("src/renderer/src"), "@locales": resolve("src/locales"), }, }, - plugins: [svgr(), react(), vanillaExtractPlugin(), bytecodePlugin()], + plugins: [ + svgr(), + react(), + vanillaExtractPlugin(), + bytecodePlugin(), + sentryPlugin, + ], }, }; }); diff --git a/package.json b/package.json index 60f05f45..df94702f 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "@reduxjs/toolkit": "^2.2.3", "@sentry/electron": "^4.23.0", "@sentry/react": "^7.111.0", + "@sentry/vite-plugin": "^2.16.1", "@vanilla-extract/css": "^1.14.2", "@vanilla-extract/recipes": "^0.5.2", "axios": "^1.6.8", diff --git a/resources/tray-icon.png b/resources/tray-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a6b4fb0394b0b75928ed61b8d601ec060a6039ea GIT binary patch literal 178866 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�fJ^&$G5n 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 literal 0 HcmV?d00001 diff --git a/src/main/services/window-manager.ts b/src/main/services/window-manager.ts index 766eb826..0aa8afd2 100644 --- a/src/main/services/window-manager.ts +++ b/src/main/services/window-manager.ts @@ -3,7 +3,7 @@ import { is } from "@electron-toolkit/utils"; import { t } from "i18next"; import path from "node:path"; import icon from "../../../resources/icon.png?asset"; -import trayIcon from "../../../resources/icon.png?asset"; +import trayIcon from "../../../resources/tray-icon.png?asset"; export class WindowManager { public static mainWindow: Electron.BrowserWindow | null = null; diff --git a/yarn.lock b/yarn.lock index e708f28d..cfe9034a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -33,7 +33,7 @@ resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz" integrity sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ== -"@babel/core@^7.21.3", "@babel/core@^7.23.5", "@babel/core@^7.23.9": +"@babel/core@^7.18.5", "@babel/core@^7.21.3", "@babel/core@^7.23.5", "@babel/core@^7.23.9": version "7.24.4" resolved "https://registry.npmjs.org/@babel/core/-/core-7.24.4.tgz" integrity sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg== @@ -904,6 +904,11 @@ "@sentry/types" "7.111.0" "@sentry/utils" "7.111.0" +"@sentry/babel-plugin-component-annotate@2.16.1": + version "2.16.1" + resolved "https://registry.yarnpkg.com/@sentry/babel-plugin-component-annotate/-/babel-plugin-component-annotate-2.16.1.tgz#da3bf4ec1c1dc68a97d6a7e27bd710001d6b07fb" + integrity sha512-pJka66URsqQbk6hTs9H1XFpUeI0xxuqLYf9Dy5pRGNHSJMtfv91U+CaYSWt03aRRMGDXMduh62zAAY7Wf0HO+A== + "@sentry/browser@7.110.0": version "7.110.0" resolved "https://registry.npmjs.org/@sentry/browser/-/browser-7.110.0.tgz" @@ -930,6 +935,74 @@ "@sentry/types" "7.111.0" "@sentry/utils" "7.111.0" +"@sentry/bundler-plugin-core@2.16.1": + version "2.16.1" + resolved "https://registry.yarnpkg.com/@sentry/bundler-plugin-core/-/bundler-plugin-core-2.16.1.tgz#9e053ac33954535c0f0e96fa7a7330a9e7ebac2e" + integrity sha512-n6z8Ts3T9HROLuY7tVEYpBKvS+P7+b8NdqxP7QBcwp2nuPUlN5Ola1ivFjk1p5a7wRYeN9zM8orGe4l2HeNfYA== + dependencies: + "@babel/core" "^7.18.5" + "@sentry/babel-plugin-component-annotate" "2.16.1" + "@sentry/cli" "^2.22.3" + dotenv "^16.3.1" + find-up "^5.0.0" + glob "^9.3.2" + magic-string "0.30.8" + unplugin "1.0.1" + +"@sentry/cli-darwin@2.31.0": + version "2.31.0" + resolved "https://registry.yarnpkg.com/@sentry/cli-darwin/-/cli-darwin-2.31.0.tgz#59e0805db8926a55676c74690e5083a0a78ae11f" + integrity sha512-VM5liyxMnm4K2g0WsrRPXRCMLhaT09C7gK5Fz/CxKYh9sbMZB7KA4hV/3klkyuyw1+ECF1J66cefhNkFZepUig== + +"@sentry/cli-linux-arm64@2.31.0": + version "2.31.0" + resolved "https://registry.yarnpkg.com/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.31.0.tgz#38604d2d1e7c2e50d48610d38523e371d2104cd7" + integrity sha512-eENJTmXoFX3uNr8xRW7Bua2Sw3V1tylQfdtS85pNjZPdbm3U8wYQSWu2VoZkK2ASOoC+17YC8jTQxq62KWnSeQ== + +"@sentry/cli-linux-arm@2.31.0": + version "2.31.0" + resolved "https://registry.yarnpkg.com/@sentry/cli-linux-arm/-/cli-linux-arm-2.31.0.tgz#6e802a279011703d39e4b31de7b950c522a73261" + integrity sha512-AZoCN3waXEfXGCd3YSrikcX/y63oQe0Tiyapkeoifq/0QhI+2MOOrAQb60gthsXwb0UDK/XeFi3PaxyUCphzxA== + +"@sentry/cli-linux-i686@2.31.0": + version "2.31.0" + resolved "https://registry.yarnpkg.com/@sentry/cli-linux-i686/-/cli-linux-i686-2.31.0.tgz#d4586a18145f43b37324231e0f19f8f23793fc58" + integrity sha512-cQUFb3brhLaNSIoNzjU/YASnTM1I3TDJP9XXzH0eLK9sSopCcDcc6OrYEYvdjJXZKzFv5sbc9UNMsIDbh4+rYg== + +"@sentry/cli-linux-x64@2.31.0": + version "2.31.0" + resolved "https://registry.yarnpkg.com/@sentry/cli-linux-x64/-/cli-linux-x64-2.31.0.tgz#f89fd87b47a5eb10c292846f3a1a754cf97105fe" + integrity sha512-z1zTNg91nZJRdcGHC/bCU1KwIaifV0MLJteip9KrFDprzhJk1HtMxFOS0+OZ5/UH21CjAFmg9Pj6IAGqm3BYjA== + +"@sentry/cli-win32-i686@2.31.0": + version "2.31.0" + resolved "https://registry.yarnpkg.com/@sentry/cli-win32-i686/-/cli-win32-i686-2.31.0.tgz#cb3dbb539c8f8bcac4b1f95ab45a87b5143997ee" + integrity sha512-+K7fdk57aUd4CmYrQfDGYPzVyxsTnVro6IPb5QSSLpP03dL7ko5208epu4m2SyN/MkFvscy9Di3n3DTvIfDU2w== + +"@sentry/cli-win32-x64@2.31.0": + version "2.31.0" + resolved "https://registry.yarnpkg.com/@sentry/cli-win32-x64/-/cli-win32-x64-2.31.0.tgz#8ac3fa4ae0634911af4f4a497d58d2adce0f303a" + integrity sha512-w5cvpZ6VVlhlyleY8TYHmrP7g48vKHnoVt5xFccfxT+HqQI/AxodvzgVvBTM2kB/sh/kHwexp6bJGWCdkGftww== + +"@sentry/cli@^2.22.3": + version "2.31.0" + resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-2.31.0.tgz#a659216576fef56733de659057d6b9039d0b64e9" + integrity sha512-nCESoXAG3kRUO5n3QbDYAqX6RU3z1ORjnd7a3sqijYsCGHfOpcjGdS7JYLVg5if+tXMEF5529BPXFe5Kg/J9tw== + dependencies: + https-proxy-agent "^5.0.0" + node-fetch "^2.6.7" + progress "^2.0.3" + proxy-from-env "^1.1.0" + which "^2.0.2" + optionalDependencies: + "@sentry/cli-darwin" "2.31.0" + "@sentry/cli-linux-arm" "2.31.0" + "@sentry/cli-linux-arm64" "2.31.0" + "@sentry/cli-linux-i686" "2.31.0" + "@sentry/cli-linux-x64" "2.31.0" + "@sentry/cli-win32-i686" "2.31.0" + "@sentry/cli-win32-x64" "2.31.0" + "@sentry/core@7.110.0": version "7.110.0" resolved "https://registry.npmjs.org/@sentry/core/-/core-7.110.0.tgz" @@ -1024,6 +1097,14 @@ dependencies: "@sentry/types" "7.111.0" +"@sentry/vite-plugin@^2.16.1": + version "2.16.1" + resolved "https://registry.yarnpkg.com/@sentry/vite-plugin/-/vite-plugin-2.16.1.tgz#47beb0d3472d053465764bfed495fe2f98189716" + integrity sha512-RSIyeqFG3PR5iJsZnagQxzOhM22z1Kh9DG+HQQsfVrxokzrWKRu/G17O2MIDh2I5iYEaL0Fkd/9RAXE4/b0aVg== + dependencies: + "@sentry/bundler-plugin-core" "2.16.1" + unplugin "1.0.1" + "@sindresorhus/is@^4.0.0", "@sindresorhus/is@^4.2.0": version "4.6.0" resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz" @@ -1594,7 +1675,7 @@ acorn-jsx@^5.3.2: resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn@^8.11.3, acorn@^8.9.0: +acorn@^8.11.3, acorn@^8.8.1, acorn@^8.9.0: version "8.11.3" resolved "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz" integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== @@ -1667,6 +1748,14 @@ any-promise@^1.0.0: resolved "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz" integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + app-builder-bin@4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-4.0.0.tgz" @@ -1888,6 +1977,11 @@ better-sqlite3@^9.5.0: bindings "^1.5.0" prebuild-install "^7.1.1" +binary-extensions@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== + bindings@^1.5.0: version "1.5.0" resolved "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz" @@ -1936,7 +2030,7 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" -braces@^3.0.2: +braces@^3.0.2, braces@~3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== @@ -2108,6 +2202,21 @@ check-disk-space@^3.4.0: resolved "https://registry.npmjs.org/check-disk-space/-/check-disk-space-3.4.0.tgz" integrity sha512-drVkSqfwA+TvuEhFipiR1OC9boEGZL5RrWvVsOthdcvQNXyCCuKkEiTOTXZ7qxSf/GLwq4GvzfrQD/Wz325hgw== +chokidar@^3.5.3: + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + chownr@^1.1.1: version "1.1.4" resolved "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz" @@ -2568,7 +2677,7 @@ dotenv-expand@^5.1.0: resolved "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz" integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA== -dotenv@^16.0.3: +dotenv@^16.0.3, dotenv@^16.3.1: version "16.4.5" resolved "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz" integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg== @@ -3342,7 +3451,7 @@ github-from-package@0.0.0: resolved "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz" integrity sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw== -glob-parent@^5.1.2: +glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== @@ -3379,6 +3488,16 @@ glob@^7.1.3, glob@^7.1.6: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^9.3.2: + version "9.3.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-9.3.5.tgz#ca2ed8ca452781a3009685607fdf025a899dfe21" + integrity sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q== + dependencies: + fs.realpath "^1.0.0" + minimatch "^8.0.2" + minipass "^4.2.4" + path-scurry "^1.6.1" + global-agent@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz" @@ -3613,7 +3732,7 @@ http2-wrapper@^2.1.10, http2-wrapper@^2.2.0: quick-lru "^5.1.1" resolve-alpn "^1.2.0" -https-proxy-agent@^5.0.1: +https-proxy-agent@^5.0.0, https-proxy-agent@^5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz" integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== @@ -3745,6 +3864,13 @@ is-bigint@^1.0.1: dependencies: has-bigints "^1.0.1" +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + is-boolean-object@^1.1.0: version "1.1.2" resolved "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz" @@ -3810,7 +3936,7 @@ is-generator-function@^1.0.10: dependencies: has-tostringtag "^1.0.0" -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== @@ -4199,6 +4325,13 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +magic-string@0.30.8: + version "0.30.8" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.8.tgz#14e8624246d2bedba70d5462aa99ac9681844613" + integrity sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ== + dependencies: + "@jridgewell/sourcemap-codec" "^1.4.15" + magic-string@^0.30.5: version "0.30.10" resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz" @@ -4295,6 +4428,13 @@ minimatch@^5.0.1, minimatch@^5.1.1: dependencies: brace-expansion "^2.0.1" +minimatch@^8.0.2: + version "8.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-8.0.4.tgz#847c1b25c014d4e9a7f68aaf63dedd668a626229" + integrity sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA== + dependencies: + brace-expansion "^2.0.1" + minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.6: version "1.2.8" resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" @@ -4307,6 +4447,11 @@ minipass@^3.0.0: dependencies: yallist "^4.0.0" +minipass@^4.2.4: + version "4.2.8" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.2.8.tgz#f0010f64393ecfc1d1ccb5f582bcaf45f48e1a3a" + integrity sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ== + minipass@^5.0.0, "minipass@^5.0.0 || ^6.0.2 || ^7.0.0": version "5.0.0" resolved "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz" @@ -4414,6 +4559,13 @@ node-domexception@^1.0.0: resolved "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz" integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== +node-fetch@^2.6.7: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + node-fetch@^3.3.0: version "3.3.2" resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz" @@ -4428,6 +4580,11 @@ node-releases@^2.0.14: resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz" integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + normalize-url@^6.0.1: version "6.1.0" resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz" @@ -4655,7 +4812,7 @@ path-parse@^1.0.7: resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-scurry@^1.10.2: +path-scurry@^1.10.2, path-scurry@^1.6.1: version "1.10.2" resolved "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz" integrity sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA== @@ -4683,7 +4840,7 @@ picocolors@^1.0.0: resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -picomatch@^2.3.1: +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== @@ -4917,6 +5074,13 @@ readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: string_decoder "^1.1.1" util-deprecate "^1.0.1" +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + redux-thunk@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz" @@ -5589,6 +5753,11 @@ tr46@^5.0.0: dependencies: punycode "^2.3.1" +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + triple-beam@^1.3.0: version "1.4.1" resolved "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz" @@ -5752,6 +5921,16 @@ universalify@^2.0.0: resolved "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz" integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== +unplugin@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/unplugin/-/unplugin-1.0.1.tgz#83b528b981cdcea1cad422a12cd02e695195ef3f" + integrity sha512-aqrHaVBWW1JVKBHmGo33T5TxeL0qWzfvjWokObHA9bYmN7eNDkwOxmLjhioHl9878qDFMAaT51XNroRyuz7WxA== + dependencies: + acorn "^8.8.1" + chokidar "^3.5.3" + webpack-sources "^3.2.3" + webpack-virtual-modules "^0.5.0" + update-browserslist-db@^1.0.13: version "1.0.13" resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz" @@ -5857,11 +6036,26 @@ web-streams-polyfill@^3.0.3: resolved "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz" integrity sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw== +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + webidl-conversions@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz" integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== +webpack-sources@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" + integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== + +webpack-virtual-modules@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/webpack-virtual-modules/-/webpack-virtual-modules-0.5.0.tgz#362f14738a56dae107937ab98ea7062e8bdd3b6c" + integrity sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw== + whatwg-encoding@^3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz" @@ -5882,6 +6076,14 @@ whatwg-url@^14.0.0: tr46 "^5.0.0" webidl-conversions "^7.0.0" +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + which-boxed-primitive@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz" @@ -5932,7 +6134,7 @@ which-typed-array@^1.1.14, which-typed-array@^1.1.15, which-typed-array@^1.1.9: gopd "^1.0.1" has-tostringtag "^1.0.2" -which@^2.0.1: +which@^2.0.1, which@^2.0.2: version "2.0.2" resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== From a4df6e9babe75bff40746f7fc562adc0815411a3 Mon Sep 17 00:00:00 2001 From: Hydra Date: Sun, 28 Apr 2024 05:59:06 +0100 Subject: [PATCH 108/140] feat: adding tray icon --- .gitignore | 3 + electron.vite.config.ts | 27 +++- package.json | 1 + resources/tray-icon.png | Bin 0 -> 178866 bytes src/main/services/window-manager.ts | 2 +- yarn.lock | 222 ++++++++++++++++++++++++++-- 6 files changed, 241 insertions(+), 14 deletions(-) create mode 100644 resources/tray-icon.png diff --git a/.gitignore b/.gitignore index 3cb8d1ca..0767dd62 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,6 @@ out *.log* .env .vite + +# Sentry Config File +.env.sentry-build-plugin diff --git a/electron.vite.config.ts b/electron.vite.config.ts index d3265042..3bb8eb01 100644 --- a/electron.vite.config.ts +++ b/electron.vite.config.ts @@ -8,14 +8,21 @@ import { } from "electron-vite"; import react from "@vitejs/plugin-react"; import { vanillaExtractPlugin } from "@vanilla-extract/vite-plugin"; +import { sentryVitePlugin } from "@sentry/vite-plugin"; import svgr from "vite-plugin-svgr"; - export default defineConfig(({ mode }) => { loadEnv(mode); + const sentryPlugin = sentryVitePlugin({ + authToken: process.env.SENTRY_AUTH_TOKEN, + org: "hydra-launcher", + project: "hydra-launcher", + }); + return { main: { build: { + sourcemap: true, rollupOptions: { external: ["better-sqlite3"], }, @@ -26,19 +33,33 @@ export default defineConfig(({ mode }) => { "@locales": resolve("src/locales"), }, }, - plugins: [externalizeDepsPlugin(), swcPlugin(), bytecodePlugin()], + plugins: [ + externalizeDepsPlugin(), + swcPlugin(), + bytecodePlugin(), + sentryPlugin, + ], }, preload: { plugins: [externalizeDepsPlugin()], }, renderer: { + build: { + sourcemap: true, + }, resolve: { alias: { "@renderer": resolve("src/renderer/src"), "@locales": resolve("src/locales"), }, }, - plugins: [svgr(), react(), vanillaExtractPlugin(), bytecodePlugin()], + plugins: [ + svgr(), + react(), + vanillaExtractPlugin(), + bytecodePlugin(), + sentryPlugin, + ], }, }; }); diff --git a/package.json b/package.json index 60f05f45..df94702f 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "@reduxjs/toolkit": "^2.2.3", "@sentry/electron": "^4.23.0", "@sentry/react": "^7.111.0", + "@sentry/vite-plugin": "^2.16.1", "@vanilla-extract/css": "^1.14.2", "@vanilla-extract/recipes": "^0.5.2", "axios": "^1.6.8", diff --git a/resources/tray-icon.png b/resources/tray-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..a6b4fb0394b0b75928ed61b8d601ec060a6039ea GIT binary patch literal 178866 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�fJ^&$G5n z5OQ(ia;%6uJfCTS$?S|7-lnw$*UDBE2)O$Fs+4ZkVMye;nkD%(Nb;$dq@#f2ldqx< zni?vH44fp4rkqaonQtgtTbt_Q$l=tu@L=MSprl(L8e;ZjY!nLLHdFtr*;}`N%Q!al ze%^kzdEp^5tB=2T{O4nUB|W*mB?lHgY^kAhVHa|62CIB#XKym+!?e~I9N=%uYE8&`*|jry|Hc>lHqW?_djbc-WThcq}laCMsa z9<-dkQb2{n$>ZF{UybY=pFK2PaW#vhNx*YbS}9}7HJ-K47M?xim}|vn&0Nv4dw3(?|PZ&*594GX7}`5Q^pehhL=kXJLA6Zdf{{+ zr?@y`ft||aIXhl0vHc#i@%e>izOy-bm9<>BxMuO+Kkx2UpvS2?L8W-+io{8;#4bPg zJ8{KTjbX`yjzt`wpPy$=W%OElX0N}dvw+bQFVzhS(c5FR76$1pj^R^mW$@_OxjFs8 z+WhL@$=mM~U1rWukDogwHt+wUjsMo=)JLyami~!-55tW(SkvnA0Y#>grnjLiGxX}F za~K?LTAi}N(<5yz!)FP`hJWwc>}BL8HT3lNpZeHY=pmrA^F;6Yo{km)qla@kOkA~8 zuC0yj{{60+VQZAF^e=Y~rb7y!cWf#8t$j#5h(V>;llv(rgQLKPw8uw#+0xF;QoC-y zcjBMx{QF8JZ?(6~bV-?=ceBLs_9~`X*WL4-Cx3`NIb&O;l+VMfIqwZP*zf-7d~>x9kb)0l(H<0mih-n~ zoU%P|nIX%pjg2|wK~HABVt6hz#h_)%>BdIKqGvPX_lX@~u@b)EBfiD&+q#9RUMwO{ z8FskLT?O5^o zai8TkHqBIK-N2OYpXH~2=y(0K7yop<{Ws&hKjj>-QHzov+#L+l)enRn-ZwqT@kqtP z{CmHqiOT=G;GULqZx3s4)!xX1eqJ+utF<>vzSC%kQg+)KbTGF3UhnPv{ld!1mlZ$X z{1voN?cl^nK`Ac=#mzTLB^s7%CY>|96Myu<1p&QXFOmwMzumuI=o|+xNb{FmrSIW|fCquC4GsVbkQqdEoP!dJlsMYqr(@ z+mJq0xN+e@$4#$6OYOBa!cS!^xf#Rj#KEB#xM~`s$CSfDOver^J+jD^`{UdE`s_b* z-q$^M+Y9;_uP<(HRcGSoXNCEDY@XN` z$$Q}pqsFFxvGW+Bh0@IR9in&dfA1_GyEEb0oJ+?#3pb^{){s~%;FOkH$INyiXVW}| zga?^STAa_$%x`Yor}gXiZ^a!hAzcbP90b@DDlJ-{%C#DF804lf_^*jpzxU(V_4xL4 zkF3_U*xTM;H2vehd4HB$z$)UXJqMH)Ob>8al6zc7ETucp__*P#=Z*{;>g|5Nnd&a{ z_0p%yujfw+YPj;4^JIpH#Mzj$Qw#-CmS)edDzcTU|HSFzb46e|6XVhelN6@POmK+c z+K_Qiuj19s-X9L3=A53UE3y9SM2@}*YzmPY44!umoRKu%P%yofL-Xj19~Mmt2R>X- zU|0~eE@_Qfmw^tW!i(3^2ky+g{BgPcUB&x<*KPkRCuzC*^Yy#`?jHL!`=^*02qQapq(St*AhFPsu!~uoLB2x@6OgI@7p;mjq6o*!Rf z{^s$^?zUe$Z{0S%=pT5y`qO;)IN8gOOdSk+b2fO3%*e}>HWZyW*_UHQvB6OWh6%#{ zFF@Bb2NEY--e zw!dkrQcwO}CFWxe%v!&_YE7hG98L&vx_?07n7Z51bi1D`-R0_j95gKu-kQXSmS0a<=*bw}59K4{f?rRu{PP%Jzzj zi%y+fzOU}+tKa|kJluXgc6;67w)FX~t0!N#{++wgEw=E55`TkVMwYzQnTIo1{q^bI zfBO%Qo_@nj;RLRRxFcc=55DGC{SIW8uaJn{^gC$E@6#)C*Df^MDB8b1wmrZ8`J3Nz zv74W9dP~1%@?O98{_3akCU4F^6E)yAsYHbJ45J%vf(g@>m}+0zxrZU`qSSQt1<{*k zZH*9kb0nn1c=qG%zD`EE^~FDCp89p&mcdH!s}j?h#Pq6pj2CYH+Z&RhBPDbrm&Gm6 zmTkKDfvd;T3g;+I3>8V*nELy6%zrb+ggEZ&0rvj?f?2FrF>vf!|LCEirH7`f;#tN! zuTBbNMBX^`tH1B8O<(VjHgnc}P5%ZZw(CDizpk5{ zX6|ItA8fxYPN&}Z-Fq#^Z0T?5yB3r(F8H=|ez#KEX5WQtFTee>i&Jmwnp@Ylt$D8M zCr)zF*1n%Qan_T3zhBATcE%@9$S@{UF-(y#Vs+4e z*r)X9`d+E37f0Rxt=qt@^M3D+f3Zj6LmuXDVmiRH@yM|<+n?2M3_dU&c+7hAvjm@k zZvEFhVTNrj`ctD7ww$;6`TAql*V^qBTVGq`K3OrXv`M4r?`@U_UGW3Y+OC~ED)?CSlsy}9$mCVz?5tA~f> z!H+U74L2XIPTjii-pkil-}x{u&|mFhI(JIW(j3cOA)AcP9am9ZFqtE!Gh>-|)OH=; zPnt^VlmDFkvHvCGg>I#*kk?8+QILJs7OA$;ZFb?@ii9 z)xXx4UtPZ)d4IloeZMSI97Dw(jf#1P7_)AQF&V7Q31)cVnt$c{HiL$l{0pY@Z4;bQ z+4JnaZ=^P6*#28)U#8hLx zBwss!QAB>5*}J2^w%0!2^y{oaGsrGBkX;!!*aQAGx_};-iD7Y}>k6y}th~C&;1|6@3pGZl6x=y%qCz8&_l3kI<$C zYuz05nH*%3%^3rp{4+m!(#>g^^exfuZGw~h>_l`w24A`NYg2E*)TjB+!e%&~{=&3m zLp5WApJ0MqxPI=NQ$MzEjotoT>65wZazqG7n!gW<)s%&w$I+XW|kx^Zb8Z;Y-pekjD0B|mXn zPF0lCmLsA1I~fi_Fhu24Jw>BhZ@?V=2F);3jw zj8=|2*QigozLi=!dr3+g)2_4P0U}Hn);^0{dpVA!p?iwYByFX7WA+2rj_H*MhpT;L zn^qpo67aZoQ*O>@j~%zR&))Is+Of`!vC-1vlj^5``}*NW_W^E({{1R3N)GEoo_B@L zmR*;Z`}*3-Oy0IzyMNsa+h^8rmpMUs#UdBWXpci;v(0ov!h;sP{eQ+{OYe*`F0LvF{?f9sw{=B#F45YBkv?62*d+Lsq6?fN~H-CaI2L1@2r{L#b7yIaH= z8j(4eXnm3Vze?`DZ?;T_<_>$MJ!wM-et}%y~X{o{Is3< z<4@aaIE61=JhpQ2+-{a>nwxx1@4ubmcw37hrc&ND_jS?7+d`VY)Ay^__s<0-wj6#9 zA;w+i4z=s=Es*?(keVd;3wfEnmLoHhF*FF(WtU+=&%MdO1JE_HHX&|5J2TZ1vYwOOBQ0T8hs5 zV_Q~H!T4aKt)n=j!L+I73py6~h;Qvx5b?Yjb9r5p={CbxuJ1Bu|GvNFUhK5Jr@2gH zFYfw!TibBv@z>*~)Jjy9ZTPRLFUpRqJr&cS@*Rqx;5K51n= zK3NrJ^RxO*zz3!S$<;01EGts)#^x&9&tAGJ`k~d&+a32s7;e8}e37O)JLPKcm+Flk z)my!~_vmu%x^RiLNsnd9*8F*^g<^Ld*z`1N$E~P^vribU&(&u-9drHJtNClvk51ly zoR1yk^6(i)Qi{W8JAeEl-a5C(S200oVy+!Sbj_`@J=+3WJcHD3-nes4^Uad{N%kM^ zbgZ0xVN)y1nF|fS)_BBsGS-S65Se?eK2Vn-p-Aa8Pw$N)y_osA3uom$^2!hQ|08Fu zvxnisje8q)r>(lzxLS~<%EE!4vt;&yW7B576JmIEcUpTwS3}-uJ*QVwXPikD&rx#t zA8)IYux(?Od2qo^8_iW`eJ^d_y45%1{uBsJ=<9^H|eBE@ZEde zhjd=u-LfrL>GZQq&8RZL|DQG2+1RYP5x1=MgB(M@EbCpJP*z);1<}i@nikA^vMlD# zvfcN${PF#?J#x7oW5Q>a87wJ6`_JC}?<9P=_#@kkw=3IOd{*CA-PHBy|FfMpZIse@ z_MccCBocISd*-|AG2cGiSon~&;dmcQw8R0i?PX8dXQ(Wl+^?jSRQW#b@9X2?Doi;n z@h*SXO}{Dk>{IcNk=f1xd$ z%$JK3K5v*|Ddw6ewsp<+>nSYLGN1mA*nfOV%X!8RH!fbx&SSXX_hzr&?Au1)nQu5V z{7RpE!FSX9sXrR`^BCG*H`7!4lNTozT=C^ms-{rPvfcNi|H|oGZJRE`pwD1aCYHnP zxiZyw=ULIuku~sKM3?|a*Qej zht7u?O+Wri|ELzMYFOmTz`($l8sVAd>&u|Uz`(%400EbRCxaNCu6{1-oD!M<{Z}?5 literal 0 HcmV?d00001 diff --git a/src/main/services/window-manager.ts b/src/main/services/window-manager.ts index 766eb826..0aa8afd2 100644 --- a/src/main/services/window-manager.ts +++ b/src/main/services/window-manager.ts @@ -3,7 +3,7 @@ import { is } from "@electron-toolkit/utils"; import { t } from "i18next"; import path from "node:path"; import icon from "../../../resources/icon.png?asset"; -import trayIcon from "../../../resources/icon.png?asset"; +import trayIcon from "../../../resources/tray-icon.png?asset"; export class WindowManager { public static mainWindow: Electron.BrowserWindow | null = null; diff --git a/yarn.lock b/yarn.lock index e708f28d..cfe9034a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -33,7 +33,7 @@ resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz" integrity sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ== -"@babel/core@^7.21.3", "@babel/core@^7.23.5", "@babel/core@^7.23.9": +"@babel/core@^7.18.5", "@babel/core@^7.21.3", "@babel/core@^7.23.5", "@babel/core@^7.23.9": version "7.24.4" resolved "https://registry.npmjs.org/@babel/core/-/core-7.24.4.tgz" integrity sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg== @@ -904,6 +904,11 @@ "@sentry/types" "7.111.0" "@sentry/utils" "7.111.0" +"@sentry/babel-plugin-component-annotate@2.16.1": + version "2.16.1" + resolved "https://registry.yarnpkg.com/@sentry/babel-plugin-component-annotate/-/babel-plugin-component-annotate-2.16.1.tgz#da3bf4ec1c1dc68a97d6a7e27bd710001d6b07fb" + integrity sha512-pJka66URsqQbk6hTs9H1XFpUeI0xxuqLYf9Dy5pRGNHSJMtfv91U+CaYSWt03aRRMGDXMduh62zAAY7Wf0HO+A== + "@sentry/browser@7.110.0": version "7.110.0" resolved "https://registry.npmjs.org/@sentry/browser/-/browser-7.110.0.tgz" @@ -930,6 +935,74 @@ "@sentry/types" "7.111.0" "@sentry/utils" "7.111.0" +"@sentry/bundler-plugin-core@2.16.1": + version "2.16.1" + resolved "https://registry.yarnpkg.com/@sentry/bundler-plugin-core/-/bundler-plugin-core-2.16.1.tgz#9e053ac33954535c0f0e96fa7a7330a9e7ebac2e" + integrity sha512-n6z8Ts3T9HROLuY7tVEYpBKvS+P7+b8NdqxP7QBcwp2nuPUlN5Ola1ivFjk1p5a7wRYeN9zM8orGe4l2HeNfYA== + dependencies: + "@babel/core" "^7.18.5" + "@sentry/babel-plugin-component-annotate" "2.16.1" + "@sentry/cli" "^2.22.3" + dotenv "^16.3.1" + find-up "^5.0.0" + glob "^9.3.2" + magic-string "0.30.8" + unplugin "1.0.1" + +"@sentry/cli-darwin@2.31.0": + version "2.31.0" + resolved "https://registry.yarnpkg.com/@sentry/cli-darwin/-/cli-darwin-2.31.0.tgz#59e0805db8926a55676c74690e5083a0a78ae11f" + integrity sha512-VM5liyxMnm4K2g0WsrRPXRCMLhaT09C7gK5Fz/CxKYh9sbMZB7KA4hV/3klkyuyw1+ECF1J66cefhNkFZepUig== + +"@sentry/cli-linux-arm64@2.31.0": + version "2.31.0" + resolved "https://registry.yarnpkg.com/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.31.0.tgz#38604d2d1e7c2e50d48610d38523e371d2104cd7" + integrity sha512-eENJTmXoFX3uNr8xRW7Bua2Sw3V1tylQfdtS85pNjZPdbm3U8wYQSWu2VoZkK2ASOoC+17YC8jTQxq62KWnSeQ== + +"@sentry/cli-linux-arm@2.31.0": + version "2.31.0" + resolved "https://registry.yarnpkg.com/@sentry/cli-linux-arm/-/cli-linux-arm-2.31.0.tgz#6e802a279011703d39e4b31de7b950c522a73261" + integrity sha512-AZoCN3waXEfXGCd3YSrikcX/y63oQe0Tiyapkeoifq/0QhI+2MOOrAQb60gthsXwb0UDK/XeFi3PaxyUCphzxA== + +"@sentry/cli-linux-i686@2.31.0": + version "2.31.0" + resolved "https://registry.yarnpkg.com/@sentry/cli-linux-i686/-/cli-linux-i686-2.31.0.tgz#d4586a18145f43b37324231e0f19f8f23793fc58" + integrity sha512-cQUFb3brhLaNSIoNzjU/YASnTM1I3TDJP9XXzH0eLK9sSopCcDcc6OrYEYvdjJXZKzFv5sbc9UNMsIDbh4+rYg== + +"@sentry/cli-linux-x64@2.31.0": + version "2.31.0" + resolved "https://registry.yarnpkg.com/@sentry/cli-linux-x64/-/cli-linux-x64-2.31.0.tgz#f89fd87b47a5eb10c292846f3a1a754cf97105fe" + integrity sha512-z1zTNg91nZJRdcGHC/bCU1KwIaifV0MLJteip9KrFDprzhJk1HtMxFOS0+OZ5/UH21CjAFmg9Pj6IAGqm3BYjA== + +"@sentry/cli-win32-i686@2.31.0": + version "2.31.0" + resolved "https://registry.yarnpkg.com/@sentry/cli-win32-i686/-/cli-win32-i686-2.31.0.tgz#cb3dbb539c8f8bcac4b1f95ab45a87b5143997ee" + integrity sha512-+K7fdk57aUd4CmYrQfDGYPzVyxsTnVro6IPb5QSSLpP03dL7ko5208epu4m2SyN/MkFvscy9Di3n3DTvIfDU2w== + +"@sentry/cli-win32-x64@2.31.0": + version "2.31.0" + resolved "https://registry.yarnpkg.com/@sentry/cli-win32-x64/-/cli-win32-x64-2.31.0.tgz#8ac3fa4ae0634911af4f4a497d58d2adce0f303a" + integrity sha512-w5cvpZ6VVlhlyleY8TYHmrP7g48vKHnoVt5xFccfxT+HqQI/AxodvzgVvBTM2kB/sh/kHwexp6bJGWCdkGftww== + +"@sentry/cli@^2.22.3": + version "2.31.0" + resolved "https://registry.yarnpkg.com/@sentry/cli/-/cli-2.31.0.tgz#a659216576fef56733de659057d6b9039d0b64e9" + integrity sha512-nCESoXAG3kRUO5n3QbDYAqX6RU3z1ORjnd7a3sqijYsCGHfOpcjGdS7JYLVg5if+tXMEF5529BPXFe5Kg/J9tw== + dependencies: + https-proxy-agent "^5.0.0" + node-fetch "^2.6.7" + progress "^2.0.3" + proxy-from-env "^1.1.0" + which "^2.0.2" + optionalDependencies: + "@sentry/cli-darwin" "2.31.0" + "@sentry/cli-linux-arm" "2.31.0" + "@sentry/cli-linux-arm64" "2.31.0" + "@sentry/cli-linux-i686" "2.31.0" + "@sentry/cli-linux-x64" "2.31.0" + "@sentry/cli-win32-i686" "2.31.0" + "@sentry/cli-win32-x64" "2.31.0" + "@sentry/core@7.110.0": version "7.110.0" resolved "https://registry.npmjs.org/@sentry/core/-/core-7.110.0.tgz" @@ -1024,6 +1097,14 @@ dependencies: "@sentry/types" "7.111.0" +"@sentry/vite-plugin@^2.16.1": + version "2.16.1" + resolved "https://registry.yarnpkg.com/@sentry/vite-plugin/-/vite-plugin-2.16.1.tgz#47beb0d3472d053465764bfed495fe2f98189716" + integrity sha512-RSIyeqFG3PR5iJsZnagQxzOhM22z1Kh9DG+HQQsfVrxokzrWKRu/G17O2MIDh2I5iYEaL0Fkd/9RAXE4/b0aVg== + dependencies: + "@sentry/bundler-plugin-core" "2.16.1" + unplugin "1.0.1" + "@sindresorhus/is@^4.0.0", "@sindresorhus/is@^4.2.0": version "4.6.0" resolved "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz" @@ -1594,7 +1675,7 @@ acorn-jsx@^5.3.2: resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn@^8.11.3, acorn@^8.9.0: +acorn@^8.11.3, acorn@^8.8.1, acorn@^8.9.0: version "8.11.3" resolved "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz" integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== @@ -1667,6 +1748,14 @@ any-promise@^1.0.0: resolved "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz" integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + app-builder-bin@4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/app-builder-bin/-/app-builder-bin-4.0.0.tgz" @@ -1888,6 +1977,11 @@ better-sqlite3@^9.5.0: bindings "^1.5.0" prebuild-install "^7.1.1" +binary-extensions@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== + bindings@^1.5.0: version "1.5.0" resolved "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz" @@ -1936,7 +2030,7 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" -braces@^3.0.2: +braces@^3.0.2, braces@~3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== @@ -2108,6 +2202,21 @@ check-disk-space@^3.4.0: resolved "https://registry.npmjs.org/check-disk-space/-/check-disk-space-3.4.0.tgz" integrity sha512-drVkSqfwA+TvuEhFipiR1OC9boEGZL5RrWvVsOthdcvQNXyCCuKkEiTOTXZ7qxSf/GLwq4GvzfrQD/Wz325hgw== +chokidar@^3.5.3: + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + chownr@^1.1.1: version "1.1.4" resolved "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz" @@ -2568,7 +2677,7 @@ dotenv-expand@^5.1.0: resolved "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-5.1.0.tgz" integrity sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA== -dotenv@^16.0.3: +dotenv@^16.0.3, dotenv@^16.3.1: version "16.4.5" resolved "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz" integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg== @@ -3342,7 +3451,7 @@ github-from-package@0.0.0: resolved "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz" integrity sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw== -glob-parent@^5.1.2: +glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== @@ -3379,6 +3488,16 @@ glob@^7.1.3, glob@^7.1.6: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^9.3.2: + version "9.3.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-9.3.5.tgz#ca2ed8ca452781a3009685607fdf025a899dfe21" + integrity sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q== + dependencies: + fs.realpath "^1.0.0" + minimatch "^8.0.2" + minipass "^4.2.4" + path-scurry "^1.6.1" + global-agent@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/global-agent/-/global-agent-3.0.0.tgz" @@ -3613,7 +3732,7 @@ http2-wrapper@^2.1.10, http2-wrapper@^2.2.0: quick-lru "^5.1.1" resolve-alpn "^1.2.0" -https-proxy-agent@^5.0.1: +https-proxy-agent@^5.0.0, https-proxy-agent@^5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz" integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== @@ -3745,6 +3864,13 @@ is-bigint@^1.0.1: dependencies: has-bigints "^1.0.1" +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + is-boolean-object@^1.1.0: version "1.1.2" resolved "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz" @@ -3810,7 +3936,7 @@ is-generator-function@^1.0.10: dependencies: has-tostringtag "^1.0.0" -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== @@ -4199,6 +4325,13 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +magic-string@0.30.8: + version "0.30.8" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.8.tgz#14e8624246d2bedba70d5462aa99ac9681844613" + integrity sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ== + dependencies: + "@jridgewell/sourcemap-codec" "^1.4.15" + magic-string@^0.30.5: version "0.30.10" resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz" @@ -4295,6 +4428,13 @@ minimatch@^5.0.1, minimatch@^5.1.1: dependencies: brace-expansion "^2.0.1" +minimatch@^8.0.2: + version "8.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-8.0.4.tgz#847c1b25c014d4e9a7f68aaf63dedd668a626229" + integrity sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA== + dependencies: + brace-expansion "^2.0.1" + minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.6: version "1.2.8" resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" @@ -4307,6 +4447,11 @@ minipass@^3.0.0: dependencies: yallist "^4.0.0" +minipass@^4.2.4: + version "4.2.8" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.2.8.tgz#f0010f64393ecfc1d1ccb5f582bcaf45f48e1a3a" + integrity sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ== + minipass@^5.0.0, "minipass@^5.0.0 || ^6.0.2 || ^7.0.0": version "5.0.0" resolved "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz" @@ -4414,6 +4559,13 @@ node-domexception@^1.0.0: resolved "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz" integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== +node-fetch@^2.6.7: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + node-fetch@^3.3.0: version "3.3.2" resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz" @@ -4428,6 +4580,11 @@ node-releases@^2.0.14: resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz" integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + normalize-url@^6.0.1: version "6.1.0" resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz" @@ -4655,7 +4812,7 @@ path-parse@^1.0.7: resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-scurry@^1.10.2: +path-scurry@^1.10.2, path-scurry@^1.6.1: version "1.10.2" resolved "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz" integrity sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA== @@ -4683,7 +4840,7 @@ picocolors@^1.0.0: resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -picomatch@^2.3.1: +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== @@ -4917,6 +5074,13 @@ readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: string_decoder "^1.1.1" util-deprecate "^1.0.1" +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + redux-thunk@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/redux-thunk/-/redux-thunk-3.1.0.tgz" @@ -5589,6 +5753,11 @@ tr46@^5.0.0: dependencies: punycode "^2.3.1" +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + triple-beam@^1.3.0: version "1.4.1" resolved "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz" @@ -5752,6 +5921,16 @@ universalify@^2.0.0: resolved "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz" integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== +unplugin@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/unplugin/-/unplugin-1.0.1.tgz#83b528b981cdcea1cad422a12cd02e695195ef3f" + integrity sha512-aqrHaVBWW1JVKBHmGo33T5TxeL0qWzfvjWokObHA9bYmN7eNDkwOxmLjhioHl9878qDFMAaT51XNroRyuz7WxA== + dependencies: + acorn "^8.8.1" + chokidar "^3.5.3" + webpack-sources "^3.2.3" + webpack-virtual-modules "^0.5.0" + update-browserslist-db@^1.0.13: version "1.0.13" resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz" @@ -5857,11 +6036,26 @@ web-streams-polyfill@^3.0.3: resolved "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz" integrity sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw== +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + webidl-conversions@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz" integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== +webpack-sources@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" + integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== + +webpack-virtual-modules@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/webpack-virtual-modules/-/webpack-virtual-modules-0.5.0.tgz#362f14738a56dae107937ab98ea7062e8bdd3b6c" + integrity sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw== + whatwg-encoding@^3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz" @@ -5882,6 +6076,14 @@ whatwg-url@^14.0.0: tr46 "^5.0.0" webidl-conversions "^7.0.0" +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + which-boxed-primitive@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz" @@ -5932,7 +6134,7 @@ which-typed-array@^1.1.14, which-typed-array@^1.1.15, which-typed-array@^1.1.9: gopd "^1.0.1" has-tostringtag "^1.0.2" -which@^2.0.1: +which@^2.0.1, which@^2.0.2: version "2.0.2" resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== From 6f0357ee744c535fe57f1fc4253cf8c17799fb69 Mon Sep 17 00:00:00 2001 From: Ikko Eltociear Ashimine Date: Mon, 29 Apr 2024 00:43:08 +0900 Subject: [PATCH 109/140] Update README.md minor fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cdde5460..2ba817f3 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ pip install -r requirements.txt ## Environment variables -You'll need an SteamGridDB API Key in order to fetch the game icons on installation. +You'll need a SteamGridDB API Key in order to fetch the game icons on installation. If you want to have onlinefix as a repacker you'll need to add your credentials to the .env Once you have it, you can paste the `.env.example` file and put it on `STEAMGRIDDB_API_KEY`, `ONLINEFIX_USERNAME`, `ONLINEFIX_PASSWORD`. From 58a777e41b172064611778d4a2163e786c744c98 Mon Sep 17 00:00:00 2001 From: Ikko Eltociear Ashimine Date: Mon, 29 Apr 2024 00:43:08 +0900 Subject: [PATCH 110/140] Update README.md minor fix --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cdde5460..2ba817f3 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ pip install -r requirements.txt ## Environment variables -You'll need an SteamGridDB API Key in order to fetch the game icons on installation. +You'll need a SteamGridDB API Key in order to fetch the game icons on installation. If you want to have onlinefix as a repacker you'll need to add your credentials to the .env Once you have it, you can paste the `.env.example` file and put it on `STEAMGRIDDB_API_KEY`, `ONLINEFIX_USERNAME`, `ONLINEFIX_PASSWORD`. From 05177d5e9c81d6dca166b9c23a6bb9b9865e11bc Mon Sep 17 00:00:00 2001 From: Hydra Date: Sun, 28 Apr 2024 19:30:03 +0100 Subject: [PATCH 111/140] fix: renaming extension of postinstall script --- package.json | 2 +- src/main/main.ts | 7 + yarn.lock | 382 ++--------------------------------------------- 3 files changed, 21 insertions(+), 370 deletions(-) diff --git a/package.json b/package.json index 5ed1c74f..6eed5a1d 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "start": "electron-vite preview", "dev": "electron-vite dev", "build": "npm run typecheck && electron-vite build", - "postinstall": "electron-builder install-app-deps && node ./postinstall.js", + "postinstall": "electron-builder install-app-deps && node ./postinstall.cjs", "build:unpack": "npm run build && electron-builder --dir", "build:win": "npm run build && electron-builder --win", "build:mac": "electron-vite build && electron-builder --mac", diff --git a/src/main/main.ts b/src/main/main.ts index eb853ae6..d09f9c2f 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -22,6 +22,13 @@ import { Repack } from "./entity"; import { Notification } from "electron"; import { t } from "i18next"; import { In } from "typeorm"; +import creatWorker from "./workers/test?nodeWorker"; + +creatWorker({ workerData: "worker" }) + .on("message", (message) => { + console.log(`\nMessage from worker: ${message}`); + }) + .postMessage(""); startProcessWatcher(); diff --git a/yarn.lock b/yarn.lock index 51dd6571..638ce44f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -623,11 +623,6 @@ resolved "https://registry.yarnpkg.com/@fontsource/fira-sans/-/fira-sans-5.0.20.tgz#92d22b1289f932db1bca7bd20902544fb9706252" integrity sha512-inmUjoKPrgnO4uUaZTAgP0b6YdhDfA52axHXvdTwgLvwd2kn3ZgK52UZoxD0VnrvTOjLA/iE4oC0tNtz4nyb5g== -"@gar/promisify@^1.0.1": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" - integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== - "@humanwhocodes/config-array@^0.11.14": version "0.11.14" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" @@ -729,22 +724,6 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@npmcli/fs@^1.0.0": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-1.1.1.tgz#72f719fe935e687c56a4faecf3c03d06ba593257" - integrity sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ== - dependencies: - "@gar/promisify" "^1.0.1" - semver "^7.3.5" - -"@npmcli/move-file@^1.0.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.1.2.tgz#1a82c3e372f7cae9253eb66d72543d6b8685c674" - integrity sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg== - dependencies: - mkdirp "^1.0.4" - rimraf "^3.0.2" - "@pkgjs/parseargs@^0.11.0": version "0.11.0" resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" @@ -1344,11 +1323,6 @@ dependencies: uint8-util "^2.1.9" -"@tootallnate/once@1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" - integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== - "@tootallnate/once@2": version "2.0.0" resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" @@ -1707,11 +1681,6 @@ resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.8.10.tgz#a1337ca426aa61cef9fe15b5b28e340a72f6fa99" integrity sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw== -abbrev@1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== - abort-controller@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" @@ -1734,7 +1703,7 @@ adm-zip@^0.5.9: resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.5.12.tgz#87786328e91d54b37358d8a50f954c4cd73ba60b" integrity sha512-6TVU49mK6KZb4qG6xWaaM4C7sA/sgUMLy/JYMOzkcp3BvVLpW0fXDFQiIzAuxFCt/2+xD7fNIiPFAoLZPhVNLQ== -agent-base@6, agent-base@^6.0.2: +agent-base@6: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== @@ -1748,21 +1717,6 @@ agent-base@^7.0.2, agent-base@^7.1.0: dependencies: debug "^4.3.4" -agentkeepalive@^4.1.3: - version "4.5.0" - resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923" - integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew== - dependencies: - humanize-ms "^1.2.1" - -aggregate-error@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" - integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== - dependencies: - clean-stack "^2.0.0" - indent-string "^4.0.0" - ajv-keywords@^3.4.1: version "3.5.2" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" @@ -1863,19 +1817,6 @@ app-root-path@^3.1.0: resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-3.1.0.tgz#5971a2fc12ba170369a7a1ef018c71e6e47c2e86" integrity sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA== -"aproba@^1.0.3 || ^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" - integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== - -are-we-there-yet@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz#679df222b278c64f2cdba1175cdc00b0d96164bd" - integrity sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg== - dependencies: - delegates "^1.0.0" - readable-stream "^3.6.0" - argparse@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" @@ -2190,30 +2131,6 @@ cac@^6.7.14: resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ== -cacache@^15.2.0: - version "15.3.0" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.3.0.tgz#dc85380fb2f556fe3dda4c719bfa0ec875a7f1eb" - integrity sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ== - dependencies: - "@npmcli/fs" "^1.0.0" - "@npmcli/move-file" "^1.0.1" - chownr "^2.0.0" - fs-minipass "^2.0.0" - glob "^7.1.4" - infer-owner "^1.0.4" - lru-cache "^6.0.0" - minipass "^3.1.1" - minipass-collect "^1.0.2" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.2" - mkdirp "^1.0.3" - p-map "^4.0.0" - promise-inflight "^1.0.1" - rimraf "^3.0.2" - ssri "^8.0.1" - tar "^6.0.2" - unique-filename "^1.1.1" - cacheable-lookup@^5.0.3: version "5.0.4" resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005" @@ -2343,11 +2260,6 @@ classnames@^2.5.1: resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.5.1.tgz#ba774c614be0f016da105c858e7159eae8e7687b" integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow== -clean-stack@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" - integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== - cli-highlight@^2.1.11: version "2.1.11" resolved "https://registry.yarnpkg.com/cli-highlight/-/cli-highlight-2.1.11.tgz#49736fa452f0aaf4fae580e30acb26828d2dc1bf" @@ -2425,11 +2337,6 @@ color-string@^1.6.0: color-name "^1.0.0" simple-swizzle "^0.2.2" -color-support@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" - integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== - color.js@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/color.js/-/color.js-1.2.0.tgz#18d9f55545111730d25ccf18ea8b6933c71440d7" @@ -2486,11 +2393,6 @@ config-file-ts@^0.2.4: glob "^10.3.10" typescript "^5.3.3" -console-control-strings@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== - convert-source-map@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" @@ -2607,7 +2509,7 @@ dayjs@^1.11.9: resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.10.tgz#68acea85317a6e164457d6d6947564029a6a16a0" integrity sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ== -debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4: +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -2679,11 +2581,6 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== -delegates@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== - detect-libc@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.3.tgz#f0cd503b40f9939b894697d19ad50895e30cf700" @@ -2871,13 +2768,6 @@ enabled@2.0.x: resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2" integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ== -encoding@^0.1.12: - version "0.1.13" - resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" - integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== - dependencies: - iconv-lite "^0.6.2" - end-of-stream@^1.1.0, end-of-stream@^1.4.1: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" @@ -3499,20 +3389,6 @@ functions-have-names@^1.2.3: resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== -gauge@^4.0.3: - version "4.0.4" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-4.0.4.tgz#52ff0652f2bbf607a989793d53b751bef2328dce" - integrity sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg== - dependencies: - aproba "^1.0.3 || ^2.0.0" - color-support "^1.1.3" - console-control-strings "^1.1.0" - has-unicode "^2.0.1" - signal-exit "^3.0.7" - string-width "^4.2.3" - strip-ansi "^6.0.1" - wide-align "^1.1.5" - generative-bayesian-network@^2.1.50: version "2.1.50" resolved "https://registry.yarnpkg.com/generative-bayesian-network/-/generative-bayesian-network-2.1.50.tgz#a576130befe0e30ccfebe5280fb2550649abadc9" @@ -3598,7 +3474,7 @@ glob@^10.3.10: minipass "^7.0.4" path-scurry "^1.10.2" -glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: +glob@^7.1.3, glob@^7.1.6: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -3717,7 +3593,7 @@ got@^13.0.0: p-cancelable "^3.0.0" responselike "^3.0.0" -graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.6: +graceful-fs@^4.1.6, graceful-fs@^4.2.0: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -3766,11 +3642,6 @@ has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: dependencies: has-symbols "^1.0.3" -has-unicode@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== - hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" @@ -3821,20 +3692,11 @@ html-parse-stringify@^3.0.1: dependencies: void-elements "3.1.0" -http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0, http-cache-semantics@^4.1.1: +http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== -http-proxy-agent@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" - integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== - dependencies: - "@tootallnate/once" "1" - agent-base "6" - debug "4" - http-proxy-agent@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz#5129800203520d434f142bc78ff3c170800f2b43" @@ -3884,13 +3746,6 @@ https-proxy-agent@^7.0.2: agent-base "^7.0.2" debug "4" -humanize-ms@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" - integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== - dependencies: - ms "^2.0.0" - i18next-browser-languagedetector@^7.2.1: version "7.2.1" resolved "https://registry.yarnpkg.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-7.2.1.tgz#1968196d437b4c8db847410c7c33554f6c448f6f" @@ -3953,16 +3808,6 @@ imurmurhash@^0.1.4: resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== -indent-string@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" - integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== - -infer-owner@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" - integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== - inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -3990,14 +3835,6 @@ internal-slot@^1.0.7: hasown "^2.0.0" side-channel "^1.0.4" -ip-address@^9.0.5: - version "9.0.5" - resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-9.0.5.tgz#117a960819b08780c3bd1f14ef3c1cc1d3f3ea5a" - integrity sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g== - dependencies: - jsbn "1.1.0" - sprintf-js "^1.1.3" - is-array-buffer@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" @@ -4109,11 +3946,6 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" -is-lambda@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" - integrity sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ== - is-map@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e" @@ -4284,11 +4116,6 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" -jsbn@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040" - integrity sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A== - jsdom@^24.0.0: version "24.0.0" resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-24.0.0.tgz#e2dc04e4c79da368481659818ee2b0cd7c39007c" @@ -4538,28 +4365,6 @@ magnet-uri@^7.0.5: bep53-range "^2.0.0" uint8-util "^2.1.9" -make-fetch-happen@^9.1.0: - version "9.1.0" - resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz#53085a09e7971433e6765f7971bf63f4e05cb968" - integrity sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg== - dependencies: - agentkeepalive "^4.1.3" - cacache "^15.2.0" - http-cache-semantics "^4.1.0" - http-proxy-agent "^4.0.1" - https-proxy-agent "^5.0.0" - is-lambda "^1.0.1" - lru-cache "^6.0.0" - minipass "^3.1.3" - minipass-collect "^1.0.2" - minipass-fetch "^1.3.2" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.4" - negotiator "^0.6.2" - promise-retry "^2.0.1" - socks-proxy-agent "^6.0.0" - ssri "^8.0.0" - matcher@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/matcher/-/matcher-3.0.0.tgz#bd9060f4c5b70aa8041ccc6f80368760994f30ca" @@ -4659,46 +4464,7 @@ minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.6: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== -minipass-collect@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617" - integrity sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA== - dependencies: - minipass "^3.0.0" - -minipass-fetch@^1.3.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-1.4.1.tgz#d75e0091daac1b0ffd7e9d41629faff7d0c1f1b6" - integrity sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw== - dependencies: - minipass "^3.1.0" - minipass-sized "^1.0.3" - minizlib "^2.0.0" - optionalDependencies: - encoding "^0.1.12" - -minipass-flush@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373" - integrity sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw== - dependencies: - minipass "^3.0.0" - -minipass-pipeline@^1.2.2, minipass-pipeline@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c" - integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A== - dependencies: - minipass "^3.0.0" - -minipass-sized@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/minipass-sized/-/minipass-sized-1.0.3.tgz#70ee5a7c5052070afacfbc22977ea79def353b70" - integrity sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g== - dependencies: - minipass "^3.0.0" - -minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3: +minipass@^3.0.0: version "3.3.6" resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== @@ -4720,7 +4486,7 @@ minipass@^5.0.0: resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c" integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== -minizlib@^2.0.0, minizlib@^2.1.1: +minizlib@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== @@ -4733,7 +4499,7 @@ mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3: resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== -mkdirp@^1.0.3, mkdirp@^1.0.4: +mkdirp@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== @@ -4763,7 +4529,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@^2.0.0, ms@^2.1.1: +ms@^2.1.1: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -4792,11 +4558,6 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -negotiator@^0.6.2: - version "0.6.3" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" - integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== - no-case@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" @@ -4817,11 +4578,6 @@ node-addon-api@^1.6.3: resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-1.7.2.tgz#3df30b95720b53c24e59948b49532b662444f54d" integrity sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg== -node-addon-api@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.1.0.tgz#71f609369379c08e251c558527a107107b5e0fdb" - integrity sha512-mNcltoe1R8o7STTegSOHdnJNN7s5EUvhoS7ShnTHDyOSd+8H+UdWODq6qSv67PjC8Zc5JRT8+oLAMCr0SIXw7g== - node-domexception@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" @@ -4843,34 +4599,11 @@ node-fetch@^3.3.0: fetch-blob "^3.1.4" formdata-polyfill "^4.0.10" -node-gyp@8.x: - version "8.4.1" - resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-8.4.1.tgz#3d49308fc31f768180957d6b5746845fbd429937" - integrity sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w== - dependencies: - env-paths "^2.2.0" - glob "^7.1.4" - graceful-fs "^4.2.6" - make-fetch-happen "^9.1.0" - nopt "^5.0.0" - npmlog "^6.0.0" - rimraf "^3.0.2" - semver "^7.3.5" - tar "^6.1.2" - which "^2.0.2" - node-releases@^2.0.14: version "2.0.14" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== -nopt@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" - integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== - dependencies: - abbrev "1" - normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" @@ -4886,16 +4619,6 @@ normalize-url@^8.0.0: resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-8.0.1.tgz#9b7d96af9836577c58f5883e939365fa15623a4a" integrity sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w== -npmlog@^6.0.0: - version "6.0.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-6.0.2.tgz#c8166017a42f2dea92d6453168dd865186a70830" - integrity sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg== - dependencies: - are-we-there-yet "^3.0.0" - console-control-strings "^1.1.0" - gauge "^4.0.3" - set-blocking "^2.0.0" - nwsapi@^2.2.7: version "2.2.9" resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.9.tgz#7f3303218372db2e9f27c27766bcfc59ae7e61c6" @@ -5040,13 +4763,6 @@ p-locate@^5.0.0: dependencies: p-limit "^3.0.2" -p-map@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" - integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== - dependencies: - aggregate-error "^3.0.0" - parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -5225,11 +4941,6 @@ progress@^2.0.3: resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== -promise-inflight@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" - integrity sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g== - promise-retry@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22" @@ -5640,11 +5351,6 @@ serialize-error@^7.0.1: dependencies: type-fest "^0.13.1" -set-blocking@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== - set-function-length@^1.2.1: version "1.2.2" resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" @@ -5697,11 +5403,6 @@ side-channel@^1.0.4, side-channel@^1.0.6: get-intrinsic "^1.2.4" object-inspect "^1.13.1" -signal-exit@^3.0.7: - version "3.0.7" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" - integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== - signal-exit@^4.0.1: version "4.1.0" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" @@ -5749,7 +5450,7 @@ slice-ansi@^3.0.0: astral-regex "^2.0.0" is-fullwidth-code-point "^3.0.0" -smart-buffer@^4.0.2, smart-buffer@^4.2.0: +smart-buffer@^4.0.2: version "4.2.0" resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== @@ -5762,23 +5463,6 @@ snake-case@^3.0.4: dot-case "^3.0.4" tslib "^2.0.3" -socks-proxy-agent@^6.0.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz#2687a31f9d7185e38d530bef1944fe1f1496d6ce" - integrity sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ== - dependencies: - agent-base "^6.0.2" - debug "^4.3.3" - socks "^2.6.2" - -socks@^2.6.2: - version "2.8.3" - resolved "https://registry.yarnpkg.com/socks/-/socks-2.8.3.tgz#1ebd0f09c52ba95a09750afe3f3f9f724a800cb5" - integrity sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw== - dependencies: - ip-address "^9.0.5" - smart-buffer "^4.2.0" - source-map-js@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af" @@ -5797,30 +5481,11 @@ source-map@^0.6.0: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -sprintf-js@^1.1.2, sprintf-js@^1.1.3: +sprintf-js@^1.1.2: version "1.1.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a" integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA== -sqlite3@^5.1.7: - version "5.1.7" - resolved "https://registry.yarnpkg.com/sqlite3/-/sqlite3-5.1.7.tgz#59ca1053c1ab38647396586edad019b1551041b7" - integrity sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog== - dependencies: - bindings "^1.5.0" - node-addon-api "^7.0.0" - prebuild-install "^7.1.1" - tar "^6.1.11" - optionalDependencies: - node-gyp "8.x" - -ssri@^8.0.0, ssri@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af" - integrity sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ== - dependencies: - minipass "^3.1.1" - stack-trace@0.0.x: version "0.0.10" resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" @@ -5840,7 +5505,7 @@ stat-mode@^1.0.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -6007,7 +5672,7 @@ tar-stream@^2.1.4: inherits "^2.0.3" readable-stream "^3.1.1" -tar@^6.0.2, tar@^6.1.11, tar@^6.1.12, tar@^6.1.2: +tar@^6.1.12: version "6.2.1" resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== @@ -6245,20 +5910,6 @@ undici-types@~5.26.4: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== -unique-filename@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" - integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== - dependencies: - unique-slug "^2.0.0" - -unique-slug@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" - integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== - dependencies: - imurmurhash "^0.1.4" - universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" @@ -6494,13 +6145,6 @@ which@^2.0.1, which@^2.0.2: dependencies: isexe "^2.0.0" -wide-align@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" - integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== - dependencies: - string-width "^1.0.2 || 2 || 3 || 4" - windows-1251@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/windows-1251/-/windows-1251-3.0.4.tgz#984b9f2e76befd9ec2e825f9fe77b681fadcdb55" From 5bec457ba621307340da2980fc3cd76ab97cf5c7 Mon Sep 17 00:00:00 2001 From: Hydra Date: Sun, 28 Apr 2024 19:30:03 +0100 Subject: [PATCH 112/140] fix: renaming extension of postinstall script --- package.json | 2 +- src/main/main.ts | 7 + yarn.lock | 382 ++--------------------------------------------- 3 files changed, 21 insertions(+), 370 deletions(-) diff --git a/package.json b/package.json index 5ed1c74f..6eed5a1d 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "start": "electron-vite preview", "dev": "electron-vite dev", "build": "npm run typecheck && electron-vite build", - "postinstall": "electron-builder install-app-deps && node ./postinstall.js", + "postinstall": "electron-builder install-app-deps && node ./postinstall.cjs", "build:unpack": "npm run build && electron-builder --dir", "build:win": "npm run build && electron-builder --win", "build:mac": "electron-vite build && electron-builder --mac", diff --git a/src/main/main.ts b/src/main/main.ts index eb853ae6..d09f9c2f 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -22,6 +22,13 @@ import { Repack } from "./entity"; import { Notification } from "electron"; import { t } from "i18next"; import { In } from "typeorm"; +import creatWorker from "./workers/test?nodeWorker"; + +creatWorker({ workerData: "worker" }) + .on("message", (message) => { + console.log(`\nMessage from worker: ${message}`); + }) + .postMessage(""); startProcessWatcher(); diff --git a/yarn.lock b/yarn.lock index 51dd6571..638ce44f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -623,11 +623,6 @@ resolved "https://registry.yarnpkg.com/@fontsource/fira-sans/-/fira-sans-5.0.20.tgz#92d22b1289f932db1bca7bd20902544fb9706252" integrity sha512-inmUjoKPrgnO4uUaZTAgP0b6YdhDfA52axHXvdTwgLvwd2kn3ZgK52UZoxD0VnrvTOjLA/iE4oC0tNtz4nyb5g== -"@gar/promisify@^1.0.1": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" - integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== - "@humanwhocodes/config-array@^0.11.14": version "0.11.14" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" @@ -729,22 +724,6 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@npmcli/fs@^1.0.0": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-1.1.1.tgz#72f719fe935e687c56a4faecf3c03d06ba593257" - integrity sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ== - dependencies: - "@gar/promisify" "^1.0.1" - semver "^7.3.5" - -"@npmcli/move-file@^1.0.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.1.2.tgz#1a82c3e372f7cae9253eb66d72543d6b8685c674" - integrity sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg== - dependencies: - mkdirp "^1.0.4" - rimraf "^3.0.2" - "@pkgjs/parseargs@^0.11.0": version "0.11.0" resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" @@ -1344,11 +1323,6 @@ dependencies: uint8-util "^2.1.9" -"@tootallnate/once@1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" - integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== - "@tootallnate/once@2": version "2.0.0" resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-2.0.0.tgz#f544a148d3ab35801c1f633a7441fd87c2e484bf" @@ -1707,11 +1681,6 @@ resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.8.10.tgz#a1337ca426aa61cef9fe15b5b28e340a72f6fa99" integrity sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw== -abbrev@1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" - integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== - abort-controller@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" @@ -1734,7 +1703,7 @@ adm-zip@^0.5.9: resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.5.12.tgz#87786328e91d54b37358d8a50f954c4cd73ba60b" integrity sha512-6TVU49mK6KZb4qG6xWaaM4C7sA/sgUMLy/JYMOzkcp3BvVLpW0fXDFQiIzAuxFCt/2+xD7fNIiPFAoLZPhVNLQ== -agent-base@6, agent-base@^6.0.2: +agent-base@6: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== @@ -1748,21 +1717,6 @@ agent-base@^7.0.2, agent-base@^7.1.0: dependencies: debug "^4.3.4" -agentkeepalive@^4.1.3: - version "4.5.0" - resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923" - integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew== - dependencies: - humanize-ms "^1.2.1" - -aggregate-error@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" - integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== - dependencies: - clean-stack "^2.0.0" - indent-string "^4.0.0" - ajv-keywords@^3.4.1: version "3.5.2" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" @@ -1863,19 +1817,6 @@ app-root-path@^3.1.0: resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-3.1.0.tgz#5971a2fc12ba170369a7a1ef018c71e6e47c2e86" integrity sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA== -"aproba@^1.0.3 || ^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" - integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== - -are-we-there-yet@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz#679df222b278c64f2cdba1175cdc00b0d96164bd" - integrity sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg== - dependencies: - delegates "^1.0.0" - readable-stream "^3.6.0" - argparse@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" @@ -2190,30 +2131,6 @@ cac@^6.7.14: resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ== -cacache@^15.2.0: - version "15.3.0" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.3.0.tgz#dc85380fb2f556fe3dda4c719bfa0ec875a7f1eb" - integrity sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ== - dependencies: - "@npmcli/fs" "^1.0.0" - "@npmcli/move-file" "^1.0.1" - chownr "^2.0.0" - fs-minipass "^2.0.0" - glob "^7.1.4" - infer-owner "^1.0.4" - lru-cache "^6.0.0" - minipass "^3.1.1" - minipass-collect "^1.0.2" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.2" - mkdirp "^1.0.3" - p-map "^4.0.0" - promise-inflight "^1.0.1" - rimraf "^3.0.2" - ssri "^8.0.1" - tar "^6.0.2" - unique-filename "^1.1.1" - cacheable-lookup@^5.0.3: version "5.0.4" resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz#5a6b865b2c44357be3d5ebc2a467b032719a7005" @@ -2343,11 +2260,6 @@ classnames@^2.5.1: resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.5.1.tgz#ba774c614be0f016da105c858e7159eae8e7687b" integrity sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow== -clean-stack@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" - integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== - cli-highlight@^2.1.11: version "2.1.11" resolved "https://registry.yarnpkg.com/cli-highlight/-/cli-highlight-2.1.11.tgz#49736fa452f0aaf4fae580e30acb26828d2dc1bf" @@ -2425,11 +2337,6 @@ color-string@^1.6.0: color-name "^1.0.0" simple-swizzle "^0.2.2" -color-support@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" - integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== - color.js@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/color.js/-/color.js-1.2.0.tgz#18d9f55545111730d25ccf18ea8b6933c71440d7" @@ -2486,11 +2393,6 @@ config-file-ts@^0.2.4: glob "^10.3.10" typescript "^5.3.3" -console-control-strings@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== - convert-source-map@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" @@ -2607,7 +2509,7 @@ dayjs@^1.11.9: resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.10.tgz#68acea85317a6e164457d6d6947564029a6a16a0" integrity sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ== -debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4: +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -2679,11 +2581,6 @@ delayed-stream@~1.0.0: resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== -delegates@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" - integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== - detect-libc@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.3.tgz#f0cd503b40f9939b894697d19ad50895e30cf700" @@ -2871,13 +2768,6 @@ enabled@2.0.x: resolved "https://registry.yarnpkg.com/enabled/-/enabled-2.0.0.tgz#f9dd92ec2d6f4bbc0d5d1e64e21d61cd4665e7c2" integrity sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ== -encoding@^0.1.12: - version "0.1.13" - resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" - integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== - dependencies: - iconv-lite "^0.6.2" - end-of-stream@^1.1.0, end-of-stream@^1.4.1: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" @@ -3499,20 +3389,6 @@ functions-have-names@^1.2.3: resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== -gauge@^4.0.3: - version "4.0.4" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-4.0.4.tgz#52ff0652f2bbf607a989793d53b751bef2328dce" - integrity sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg== - dependencies: - aproba "^1.0.3 || ^2.0.0" - color-support "^1.1.3" - console-control-strings "^1.1.0" - has-unicode "^2.0.1" - signal-exit "^3.0.7" - string-width "^4.2.3" - strip-ansi "^6.0.1" - wide-align "^1.1.5" - generative-bayesian-network@^2.1.50: version "2.1.50" resolved "https://registry.yarnpkg.com/generative-bayesian-network/-/generative-bayesian-network-2.1.50.tgz#a576130befe0e30ccfebe5280fb2550649abadc9" @@ -3598,7 +3474,7 @@ glob@^10.3.10: minipass "^7.0.4" path-scurry "^1.10.2" -glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: +glob@^7.1.3, glob@^7.1.6: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -3717,7 +3593,7 @@ got@^13.0.0: p-cancelable "^3.0.0" responselike "^3.0.0" -graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.6: +graceful-fs@^4.1.6, graceful-fs@^4.2.0: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -3766,11 +3642,6 @@ has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: dependencies: has-symbols "^1.0.3" -has-unicode@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== - hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" @@ -3821,20 +3692,11 @@ html-parse-stringify@^3.0.1: dependencies: void-elements "3.1.0" -http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0, http-cache-semantics@^4.1.1: +http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== -http-proxy-agent@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" - integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== - dependencies: - "@tootallnate/once" "1" - agent-base "6" - debug "4" - http-proxy-agent@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz#5129800203520d434f142bc78ff3c170800f2b43" @@ -3884,13 +3746,6 @@ https-proxy-agent@^7.0.2: agent-base "^7.0.2" debug "4" -humanize-ms@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" - integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== - dependencies: - ms "^2.0.0" - i18next-browser-languagedetector@^7.2.1: version "7.2.1" resolved "https://registry.yarnpkg.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-7.2.1.tgz#1968196d437b4c8db847410c7c33554f6c448f6f" @@ -3953,16 +3808,6 @@ imurmurhash@^0.1.4: resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== -indent-string@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" - integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== - -infer-owner@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" - integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== - inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -3990,14 +3835,6 @@ internal-slot@^1.0.7: hasown "^2.0.0" side-channel "^1.0.4" -ip-address@^9.0.5: - version "9.0.5" - resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-9.0.5.tgz#117a960819b08780c3bd1f14ef3c1cc1d3f3ea5a" - integrity sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g== - dependencies: - jsbn "1.1.0" - sprintf-js "^1.1.3" - is-array-buffer@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" @@ -4109,11 +3946,6 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" -is-lambda@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" - integrity sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ== - is-map@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e" @@ -4284,11 +4116,6 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" -jsbn@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040" - integrity sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A== - jsdom@^24.0.0: version "24.0.0" resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-24.0.0.tgz#e2dc04e4c79da368481659818ee2b0cd7c39007c" @@ -4538,28 +4365,6 @@ magnet-uri@^7.0.5: bep53-range "^2.0.0" uint8-util "^2.1.9" -make-fetch-happen@^9.1.0: - version "9.1.0" - resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz#53085a09e7971433e6765f7971bf63f4e05cb968" - integrity sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg== - dependencies: - agentkeepalive "^4.1.3" - cacache "^15.2.0" - http-cache-semantics "^4.1.0" - http-proxy-agent "^4.0.1" - https-proxy-agent "^5.0.0" - is-lambda "^1.0.1" - lru-cache "^6.0.0" - minipass "^3.1.3" - minipass-collect "^1.0.2" - minipass-fetch "^1.3.2" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.4" - negotiator "^0.6.2" - promise-retry "^2.0.1" - socks-proxy-agent "^6.0.0" - ssri "^8.0.0" - matcher@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/matcher/-/matcher-3.0.0.tgz#bd9060f4c5b70aa8041ccc6f80368760994f30ca" @@ -4659,46 +4464,7 @@ minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.6: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== -minipass-collect@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617" - integrity sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA== - dependencies: - minipass "^3.0.0" - -minipass-fetch@^1.3.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-1.4.1.tgz#d75e0091daac1b0ffd7e9d41629faff7d0c1f1b6" - integrity sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw== - dependencies: - minipass "^3.1.0" - minipass-sized "^1.0.3" - minizlib "^2.0.0" - optionalDependencies: - encoding "^0.1.12" - -minipass-flush@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373" - integrity sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw== - dependencies: - minipass "^3.0.0" - -minipass-pipeline@^1.2.2, minipass-pipeline@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c" - integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A== - dependencies: - minipass "^3.0.0" - -minipass-sized@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/minipass-sized/-/minipass-sized-1.0.3.tgz#70ee5a7c5052070afacfbc22977ea79def353b70" - integrity sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g== - dependencies: - minipass "^3.0.0" - -minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3: +minipass@^3.0.0: version "3.3.6" resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== @@ -4720,7 +4486,7 @@ minipass@^5.0.0: resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c" integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== -minizlib@^2.0.0, minizlib@^2.1.1: +minizlib@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== @@ -4733,7 +4499,7 @@ mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3: resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== -mkdirp@^1.0.3, mkdirp@^1.0.4: +mkdirp@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== @@ -4763,7 +4529,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@^2.0.0, ms@^2.1.1: +ms@^2.1.1: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -4792,11 +4558,6 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -negotiator@^0.6.2: - version "0.6.3" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" - integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== - no-case@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" @@ -4817,11 +4578,6 @@ node-addon-api@^1.6.3: resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-1.7.2.tgz#3df30b95720b53c24e59948b49532b662444f54d" integrity sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg== -node-addon-api@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.1.0.tgz#71f609369379c08e251c558527a107107b5e0fdb" - integrity sha512-mNcltoe1R8o7STTegSOHdnJNN7s5EUvhoS7ShnTHDyOSd+8H+UdWODq6qSv67PjC8Zc5JRT8+oLAMCr0SIXw7g== - node-domexception@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" @@ -4843,34 +4599,11 @@ node-fetch@^3.3.0: fetch-blob "^3.1.4" formdata-polyfill "^4.0.10" -node-gyp@8.x: - version "8.4.1" - resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-8.4.1.tgz#3d49308fc31f768180957d6b5746845fbd429937" - integrity sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w== - dependencies: - env-paths "^2.2.0" - glob "^7.1.4" - graceful-fs "^4.2.6" - make-fetch-happen "^9.1.0" - nopt "^5.0.0" - npmlog "^6.0.0" - rimraf "^3.0.2" - semver "^7.3.5" - tar "^6.1.2" - which "^2.0.2" - node-releases@^2.0.14: version "2.0.14" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== -nopt@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" - integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== - dependencies: - abbrev "1" - normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" @@ -4886,16 +4619,6 @@ normalize-url@^8.0.0: resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-8.0.1.tgz#9b7d96af9836577c58f5883e939365fa15623a4a" integrity sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w== -npmlog@^6.0.0: - version "6.0.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-6.0.2.tgz#c8166017a42f2dea92d6453168dd865186a70830" - integrity sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg== - dependencies: - are-we-there-yet "^3.0.0" - console-control-strings "^1.1.0" - gauge "^4.0.3" - set-blocking "^2.0.0" - nwsapi@^2.2.7: version "2.2.9" resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.9.tgz#7f3303218372db2e9f27c27766bcfc59ae7e61c6" @@ -5040,13 +4763,6 @@ p-locate@^5.0.0: dependencies: p-limit "^3.0.2" -p-map@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" - integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== - dependencies: - aggregate-error "^3.0.0" - parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -5225,11 +4941,6 @@ progress@^2.0.3: resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== -promise-inflight@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" - integrity sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g== - promise-retry@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22" @@ -5640,11 +5351,6 @@ serialize-error@^7.0.1: dependencies: type-fest "^0.13.1" -set-blocking@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== - set-function-length@^1.2.1: version "1.2.2" resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" @@ -5697,11 +5403,6 @@ side-channel@^1.0.4, side-channel@^1.0.6: get-intrinsic "^1.2.4" object-inspect "^1.13.1" -signal-exit@^3.0.7: - version "3.0.7" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" - integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== - signal-exit@^4.0.1: version "4.1.0" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" @@ -5749,7 +5450,7 @@ slice-ansi@^3.0.0: astral-regex "^2.0.0" is-fullwidth-code-point "^3.0.0" -smart-buffer@^4.0.2, smart-buffer@^4.2.0: +smart-buffer@^4.0.2: version "4.2.0" resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== @@ -5762,23 +5463,6 @@ snake-case@^3.0.4: dot-case "^3.0.4" tslib "^2.0.3" -socks-proxy-agent@^6.0.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz#2687a31f9d7185e38d530bef1944fe1f1496d6ce" - integrity sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ== - dependencies: - agent-base "^6.0.2" - debug "^4.3.3" - socks "^2.6.2" - -socks@^2.6.2: - version "2.8.3" - resolved "https://registry.yarnpkg.com/socks/-/socks-2.8.3.tgz#1ebd0f09c52ba95a09750afe3f3f9f724a800cb5" - integrity sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw== - dependencies: - ip-address "^9.0.5" - smart-buffer "^4.2.0" - source-map-js@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af" @@ -5797,30 +5481,11 @@ source-map@^0.6.0: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -sprintf-js@^1.1.2, sprintf-js@^1.1.3: +sprintf-js@^1.1.2: version "1.1.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a" integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA== -sqlite3@^5.1.7: - version "5.1.7" - resolved "https://registry.yarnpkg.com/sqlite3/-/sqlite3-5.1.7.tgz#59ca1053c1ab38647396586edad019b1551041b7" - integrity sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog== - dependencies: - bindings "^1.5.0" - node-addon-api "^7.0.0" - prebuild-install "^7.1.1" - tar "^6.1.11" - optionalDependencies: - node-gyp "8.x" - -ssri@^8.0.0, ssri@^8.0.1: - version "8.0.1" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af" - integrity sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ== - dependencies: - minipass "^3.1.1" - stack-trace@0.0.x: version "0.0.10" resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" @@ -5840,7 +5505,7 @@ stat-mode@^1.0.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -6007,7 +5672,7 @@ tar-stream@^2.1.4: inherits "^2.0.3" readable-stream "^3.1.1" -tar@^6.0.2, tar@^6.1.11, tar@^6.1.12, tar@^6.1.2: +tar@^6.1.12: version "6.2.1" resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== @@ -6245,20 +5910,6 @@ undici-types@~5.26.4: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== -unique-filename@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" - integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== - dependencies: - unique-slug "^2.0.0" - -unique-slug@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" - integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== - dependencies: - imurmurhash "^0.1.4" - universalify@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" @@ -6494,13 +6145,6 @@ which@^2.0.1, which@^2.0.2: dependencies: isexe "^2.0.0" -wide-align@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" - integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== - dependencies: - string-width "^1.0.2 || 2 || 3 || 4" - windows-1251@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/windows-1251/-/windows-1251-3.0.4.tgz#984b9f2e76befd9ec2e825f9fe77b681fadcdb55" From 25fb4342d6427a9f50d2bc71e45f90991a757d7f Mon Sep 17 00:00:00 2001 From: Hydra Date: Mon, 29 Apr 2024 11:01:34 +0100 Subject: [PATCH 113/140] ci: testing pipeline --- .github/workflows/build.yml | 78 +- electron.vite.config.ts | 1 + package.json | 3 +- src/main/events/library/close-game.ts | 18 +- src/main/main.ts | 15 +- src/main/services/repack-tracker/1337x.ts | 5 +- .../services/repack-tracker/cpg-repacks.ts | 3 +- src/main/services/repack-tracker/gog.ts | 53 +- .../services/repack-tracker/online-fix.ts | 3 +- src/main/services/repack-tracker/xatab.ts | 58 +- src/main/services/window-manager.ts | 4 +- src/main/workers/torrent-parser.worker.ts | 17 + src/preload/index.d.ts | 3 +- src/preload/index.ts | 3 +- src/renderer/index.html | 3 +- .../components/bottom-panel/bottom-panel.tsx | 2 +- src/renderer/src/components/modal/modal.tsx | 12 +- src/renderer/src/declaration.d.ts | 2 +- .../src/features/use-preferences-slice.ts | 5 +- src/renderer/src/hooks/use-download.ts | 10 +- .../src/pages/downloads/downloads.tsx | 8 +- .../pages/game-details/hero-panel-actions.tsx | 6 +- .../game-details/select-folder-modal.tsx | 2 +- .../src/pages/home/search-results.tsx | 4 +- src/renderer/src/pages/settings/settings.tsx | 6 +- tsconfig.node.json | 3 +- yarn.lock | 2421 ++++++++--------- 27 files changed, 1349 insertions(+), 1399 deletions(-) create mode 100644 src/main/workers/torrent-parser.worker.ts diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 973f95bc..9eb8b0e9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,21 +8,9 @@ jobs: build: strategy: matrix: - os: - [ - { - name: windows-latest, - build_path: out/Hydra-win32-x64, - artifact: Hydra-win32-x64, - }, - { - name: ubuntu-latest, - build_path: out/Hydra-linux-x64, - artifact: Hydra-linux-x64, - }, - ] + os: [windows-latest, ubuntu-latest] - runs-on: ${{ matrix.os.name }} + runs-on: ${{ matrix.os }} steps: - name: Check out Git repository @@ -47,10 +35,10 @@ jobs: - name: Build with cx_Freeze run: python torrent-client/setup.py build - - name: Publish - run: yarn run publish + - name: Build Linux + if: matrix.os == 'ubuntu-latest' + run: yarn build:linux env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} MAIN_VITE_STEAMGRIDDB_API_KEY: ${{ secrets.STEAMGRIDDB_API_KEY }} SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} MAIN_VITE_SENTRY_DSN: ${{ vars.SENTRY_DSN }} @@ -58,15 +46,55 @@ jobs: MAIN_VITE_ONLINEFIX_USERNAME: ${{ secrets.ONLINEFIX_USERNAME }} MAIN_VITE_ONLINEFIX_PASSWORD: ${{ secrets.ONLINEFIX_PASSWORD }} - - name: VirusTotal Scan - uses: crazy-max/ghaction-virustotal@v4 - with: - vt_api_key: ${{ secrets.VT_API_KEY }} - files: | - ./hydra-download-manager/hydra-download-manager.exe + - name: Build Windows + if: matrix.os == 'windows-latest' + run: yarn build:win + env: + MAIN_VITE_STEAMGRIDDB_API_KEY: ${{ secrets.STEAMGRIDDB_API_KEY }} + SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} + MAIN_VITE_SENTRY_DSN: ${{ vars.SENTRY_DSN }} + RENDERER_VITE_SENTRY_DSN: ${{ vars.SENTRY_DSN }} + MAIN_VITE_ONLINEFIX_USERNAME: ${{ secrets.ONLINEFIX_USERNAME }} + MAIN_VITE_ONLINEFIX_PASSWORD: ${{ secrets.ONLINEFIX_PASSWORD }} - name: Create artifact uses: actions/upload-artifact@v4 with: - name: ${{ matrix.os.artifact }} - path: ${{ matrix.os.build_path }} + name: Build-${{ matrix.os }} + path: | + dist/*.exe + dist/*.zip + dist/*.dmg + dist/*.AppImage + dist/*.snap + dist/*.deb + dist/*.rpm + dist/*.tar.gz + dist/*.yml + dist/*.blockmap + + - name: VirusTotal Scan + uses: crazy-max/ghaction-virustotal@v4 + if: matrix.os == 'windows-latest' + with: + vt_api_key: ${{ secrets.VT_API_KEY }} + files: | + ./dist/*.exe + + - name: Publish + uses: softprops/action-gh-release@v1 + with: + draft: true + files: | + dist/*.exe + dist/*.zip + dist/*.dmg + dist/*.AppImage + dist/*.snap + dist/*.deb + dist/*.rpm + dist/*.tar.gz + dist/*.yml + dist/*.blockmap + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/electron.vite.config.ts b/electron.vite.config.ts index 3bb8eb01..d98d0238 100644 --- a/electron.vite.config.ts +++ b/electron.vite.config.ts @@ -31,6 +31,7 @@ export default defineConfig(({ mode }) => { alias: { "@main": resolve("src/main"), "@locales": resolve("src/locales"), + "@resources": resolve("resources"), }, }, plugins: [ diff --git a/package.json b/package.json index 6eed5a1d..e4ed2ebd 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "build": "npm run typecheck && electron-vite build", "postinstall": "electron-builder install-app-deps && node ./postinstall.cjs", "build:unpack": "npm run build && electron-builder --dir", - "build:win": "npm run build && electron-builder --win", + "build:win": "electron-builder --win", "build:mac": "electron-vite build && electron-builder --mac", "build:linux": "electron-vite build && electron-builder --linux" }, @@ -70,6 +70,7 @@ "@types/jsdom": "^21.1.6", "@types/lodash-es": "^4.17.12", "@types/node": "^20.12.7", + "@types/parse-torrent": "^5.8.7", "@types/react": "^18.2.48", "@types/react-dom": "^18.2.18", "@vanilla-extract/vite-plugin": "^4.0.7", diff --git a/src/main/events/library/close-game.ts b/src/main/events/library/close-game.ts index 0d556925..d549f3b7 100644 --- a/src/main/events/library/close-game.ts +++ b/src/main/events/library/close-game.ts @@ -1,9 +1,9 @@ import path from "node:path"; import { gameRepository } from "@main/repository"; +import { getProcesses } from "@main/helpers"; import { registerEvent } from "../register-event"; -import { getProcesses } from "@main/helpers"; const closeGame = async ( _event: Electron.IpcMainInvokeEvent, @@ -12,13 +12,17 @@ const closeGame = async ( const processes = await getProcesses(); const game = await gameRepository.findOne({ where: { id: gameId } }); - const gameProcess = processes.find((runningProcess) => { - const basename = path.win32.basename(game.executablePath); - const basenameWithoutExtension = path.win32.basename( - game.executablePath, - path.extname(game.executablePath) - ); + if (!game) return false; + const executablePath = game.executablePath!; + + const basename = path.win32.basename(executablePath); + const basenameWithoutExtension = path.win32.basename( + executablePath, + path.extname(executablePath) + ); + + const gameProcess = processes.find((runningProcess) => { if (process.platform === "win32") { return runningProcess.name === basename; } diff --git a/src/main/main.ts b/src/main/main.ts index d09f9c2f..ae591720 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -4,7 +4,7 @@ import { getNewGOGGames, getNewRepacksFromCPG, getNewRepacksFromUser, - // getNewRepacksFromXatab, + getNewRepacksFromXatab, getNewRepacksFromOnlineFix, readPipe, startProcessWatcher, @@ -22,13 +22,6 @@ import { Repack } from "./entity"; import { Notification } from "electron"; import { t } from "i18next"; import { In } from "typeorm"; -import creatWorker from "./workers/test?nodeWorker"; - -creatWorker({ workerData: "worker" }) - .on("message", (message) => { - console.log(`\nMessage from worker: ${message}`); - }) - .postMessage(""); startProcessWatcher(); @@ -80,9 +73,9 @@ const checkForNewRepacks = async () => { getNewGOGGames( existingRepacks.filter((repack) => repack.repacker === "GOG") ), - // getNewRepacksFromXatab( - // existingRepacks.filter((repack) => repack.repacker === "Xatab") - // ), + getNewRepacksFromXatab( + existingRepacks.filter((repack) => repack.repacker === "Xatab") + ), getNewRepacksFromCPG( existingRepacks.filter((repack) => repack.repacker === "CPG") ), diff --git a/src/main/services/repack-tracker/1337x.ts b/src/main/services/repack-tracker/1337x.ts index 1cbafa3b..8573079b 100644 --- a/src/main/services/repack-tracker/1337x.ts +++ b/src/main/services/repack-tracker/1337x.ts @@ -4,7 +4,6 @@ import { formatUploadDate } from "@main/helpers"; import { Repack } from "@main/entity"; import { requestWebPage, savePage } from "./helpers"; -import type { GameRepackInput } from "./helpers"; export const request1337x = async (path: string) => requestWebPage(`https://1337xx.to${path}`); @@ -68,7 +67,7 @@ export const extractTorrentsFromDocument = async ( user: string, document: Document, existingRepacks: Repack[] = [] -): Promise => { +) => { const $trs = Array.from(document.querySelectorAll("tbody tr")); return Promise.all( @@ -108,7 +107,7 @@ export const getNewRepacksFromUser = async ( user: string, existingRepacks: Repack[], page = 1 -): Promise => { +) => { const response = await request1337x(`/user/${user}/${page}`); const { window } = new JSDOM(response); diff --git a/src/main/services/repack-tracker/cpg-repacks.ts b/src/main/services/repack-tracker/cpg-repacks.ts index c4b62c1f..2b939d08 100644 --- a/src/main/services/repack-tracker/cpg-repacks.ts +++ b/src/main/services/repack-tracker/cpg-repacks.ts @@ -3,7 +3,6 @@ import { JSDOM } from "jsdom"; import { Repack } from "@main/entity"; import { requestWebPage, savePage } from "./helpers"; -import type { GameRepackInput } from "./helpers"; import { logger } from "../logger"; export const getNewRepacksFromCPG = async ( @@ -14,7 +13,7 @@ export const getNewRepacksFromCPG = async ( const { window } = new JSDOM(data); - const repacks: GameRepackInput[] = []; + const repacks = []; try { Array.from(window.document.querySelectorAll(".post")).forEach(($post) => { diff --git a/src/main/services/repack-tracker/gog.ts b/src/main/services/repack-tracker/gog.ts index 73daebf7..00c78e36 100644 --- a/src/main/services/repack-tracker/gog.ts +++ b/src/main/services/repack-tracker/gog.ts @@ -1,7 +1,8 @@ import { JSDOM, VirtualConsole } from "jsdom"; -import { GameRepackInput, requestWebPage, savePage } from "./helpers"; +import { requestWebPage, savePage } from "./helpers"; import { Repack } from "@main/entity"; -import { logger } from "../logger"; + +import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity"; const virtualConsole = new VirtualConsole(); @@ -36,43 +37,35 @@ const getGOGGame = async (url: string) => { }; export const getNewGOGGames = async (existingRepacks: Repack[] = []) => { - try { - const data = await requestWebPage( - "https://freegogpcgames.com/a-z-games-list/" - ); + const data = await requestWebPage( + "https://freegogpcgames.com/a-z-games-list/" + ); - const { window } = new JSDOM(data, { virtualConsole }); + const { window } = new JSDOM(data, { virtualConsole }); - const $uls = Array.from(window.document.querySelectorAll(".az-columns")); + const $uls = Array.from(window.document.querySelectorAll(".az-columns")); - for (const $ul of $uls) { - const repacks: GameRepackInput[] = []; - const $lis = Array.from($ul.querySelectorAll("li")); + for (const $ul of $uls) { + const repacks: QueryDeepPartialEntity[] = []; + const $lis = Array.from($ul.querySelectorAll("li")); - for (const $li of $lis) { - const $a = $li.querySelector("a"); - const href = $a.href; + for (const $li of $lis) { + const $a = $li.querySelector("a"); + const href = $a.href; - const title = $a.textContent.trim(); + const title = $a.textContent.trim(); - const gameExists = existingRepacks.some( - (existingRepack) => existingRepack.title === title - ); + const gameExists = existingRepacks.some( + (existingRepack) => existingRepack.title === title + ); - if (!gameExists) { - try { - const game = await getGOGGame(href); + if (!gameExists) { + const game = await getGOGGame(href); - repacks.push({ ...game, title }); - } catch (err) { - logger.error(err.message, { method: "getGOGGame", url: href }); - } - } + repacks.push({ ...game, title }); } - - if (repacks.length) await savePage(repacks); } - } catch (err) { - logger.error(err.message, { method: "getNewGOGGames" }); + + if (repacks.length) await savePage(repacks); } }; diff --git a/src/main/services/repack-tracker/online-fix.ts b/src/main/services/repack-tracker/online-fix.ts index 2a69dd70..c627eccb 100644 --- a/src/main/services/repack-tracker/online-fix.ts +++ b/src/main/services/repack-tracker/online-fix.ts @@ -1,6 +1,5 @@ import { Repack } from "@main/entity"; import { savePage } from "./helpers"; -import type { GameRepackInput } from "./helpers"; import { logger } from "../logger"; import parseTorrent, { toMagnetURI, @@ -85,7 +84,7 @@ export const getNewRepacksFromOnlineFix = async ( }); const document = new JSDOM(home.body).window.document; - const repacks: GameRepackInput[] = []; + const repacks = []; const articles = Array.from(document.querySelectorAll(".news")); const totalPages = Number( document.querySelector("nav > a:nth-child(13)")?.textContent diff --git a/src/main/services/repack-tracker/xatab.ts b/src/main/services/repack-tracker/xatab.ts index 847a1026..de9f5285 100644 --- a/src/main/services/repack-tracker/xatab.ts +++ b/src/main/services/repack-tracker/xatab.ts @@ -1,16 +1,14 @@ import { JSDOM } from "jsdom"; -import parseTorrent, { toMagnetURI } from "parse-torrent"; - import { Repack } from "@main/entity"; import { logger } from "../logger"; import { requestWebPage, savePage } from "./helpers"; -import type { GameRepackInput } from "./helpers"; -const getTorrentBuffer = (url: string) => - fetch(url, { method: "GET" }).then((response) => - response.arrayBuffer().then((buffer) => Buffer.from(buffer)) - ); +import createWorker from "@main/workers/torrent-parser.worker?nodeWorker"; +import { toMagnetURI } from "parse-torrent"; +import type { Instance } from "parse-torrent"; + +const worker = createWorker({}); const formatXatabDate = (str: string) => { const date = new Date(); @@ -28,29 +26,36 @@ const formatXatabDate = (str: string) => { const formatXatabDownloadSize = (str: string) => str.replace(",", ".").replace(/Гб/g, "GB").replace(/Мб/g, "MB"); -const getXatabRepack = async (url: string) => { - const data = await requestWebPage(url); - const { window } = new JSDOM(data); - const { document } = window; +const getXatabRepack = (url: string) => { + return new Promise((resolve) => { + (async () => { + const data = await requestWebPage(url); + const { window } = new JSDOM(data); + const { document } = window; - const $uploadDate = document.querySelector(".entry__date"); - const $size = document.querySelector(".entry__info-size"); + const $uploadDate = document.querySelector(".entry__date"); + const $size = document.querySelector(".entry__info-size"); - const $downloadButton = document.querySelector( - ".download-torrent" - ) as HTMLAnchorElement; + const $downloadButton = document.querySelector( + ".download-torrent" + ) as HTMLAnchorElement; - if (!$downloadButton) throw new Error("Download button not found"); + if (!$downloadButton) throw new Error("Download button not found"); - const torrentBuffer = await getTorrentBuffer($downloadButton.href); + const onMessage = (torrent: Instance) => { + resolve({ + fileSize: formatXatabDownloadSize($size.textContent).toUpperCase(), + magnet: toMagnetURI(torrent), + uploadDate: formatXatabDate($uploadDate.textContent), + }); - return { - fileSize: formatXatabDownloadSize($size.textContent).toUpperCase(), - magnet: toMagnetURI({ - infoHash: parseTorrent(torrentBuffer).infoHash, - }), - uploadDate: formatXatabDate($uploadDate.textContent), - }; + worker.removeListener("message", onMessage); + }; + + worker.on("message", onMessage); + worker.postMessage($downloadButton.href); + })(); + }); }; export const getNewRepacksFromXatab = async ( @@ -61,7 +66,7 @@ export const getNewRepacksFromXatab = async ( const { window } = new JSDOM(data); - const repacks: GameRepackInput[] = []; + const repacks = []; for (const $a of Array.from( window.document.querySelectorAll(".entry__title a") @@ -84,7 +89,6 @@ export const getNewRepacksFromXatab = async ( const newRepacks = repacks.filter( (repack) => - repack.uploadDate && !existingRepacks.some( (existingRepack) => existingRepack.title === repack.title ) diff --git a/src/main/services/window-manager.ts b/src/main/services/window-manager.ts index 0aa8afd2..05cb95d6 100644 --- a/src/main/services/window-manager.ts +++ b/src/main/services/window-manager.ts @@ -2,8 +2,8 @@ import { BrowserWindow, Menu, Tray, app } from "electron"; import { is } from "@electron-toolkit/utils"; import { t } from "i18next"; import path from "node:path"; -import icon from "../../../resources/icon.png?asset"; -import trayIcon from "../../../resources/tray-icon.png?asset"; +import icon from "@resources/icon.png?asset"; +import trayIcon from "@resources/tray-icon.png?asset"; export class WindowManager { public static mainWindow: Electron.BrowserWindow | null = null; diff --git a/src/main/workers/torrent-parser.worker.ts b/src/main/workers/torrent-parser.worker.ts new file mode 100644 index 00000000..7502fd5f --- /dev/null +++ b/src/main/workers/torrent-parser.worker.ts @@ -0,0 +1,17 @@ +import { parentPort } from "worker_threads"; +import parseTorrent from "parse-torrent"; + +const port = parentPort; +if (!port) throw new Error("IllegalState"); + +const getTorrentBuffer = (url: string) => + fetch(url, { method: "GET" }).then((response) => + response.arrayBuffer().then((buffer) => Buffer.from(buffer)) + ); + +port.on("message", async (url: string) => { + const buffer = await getTorrentBuffer(url); + const torrent = await parseTorrent(buffer); + + port.postMessage(torrent); +}); diff --git a/src/preload/index.d.ts b/src/preload/index.d.ts index 97dcca0b..4ca7b2fb 100644 --- a/src/preload/index.d.ts +++ b/src/preload/index.d.ts @@ -71,7 +71,8 @@ contextBridge.exposeInMainWorld("electron", { openGame: (gameId: number, executablePath: string) => ipcRenderer.invoke("openGame", gameId, executablePath), closeGame: (gameId: number) => ipcRenderer.invoke("closeGame", gameId), - removeGame: (gameId: number) => ipcRenderer.invoke("removeGame", gameId), + removeGameFromLibrary: (gameId: number) => + ipcRenderer.invoke("removeGameFromLibrary", gameId), deleteGameFolder: (gameId: number) => ipcRenderer.invoke("deleteGameFolder", gameId), getGameByObjectID: (objectID: string) => diff --git a/src/preload/index.ts b/src/preload/index.ts index 66fff80f..c4f8ca96 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -80,7 +80,8 @@ contextBridge.exposeInMainWorld("electron", { openGame: (gameId: number, executablePath: string) => ipcRenderer.invoke("openGame", gameId, executablePath), closeGame: (gameId: number) => ipcRenderer.invoke("closeGame", gameId), - removeGame: (gameId: number) => ipcRenderer.invoke("removeGame", gameId), + removeGameFromLibrary: (gameId: number) => + ipcRenderer.invoke("removeGameFromLibrary", gameId), deleteGameFolder: (gameId: number) => ipcRenderer.invoke("deleteGameFolder", gameId), getGameByObjectID: (objectID: string) => diff --git a/src/renderer/index.html b/src/renderer/index.html index abb1eaae..1917de45 100644 --- a/src/renderer/index.html +++ b/src/renderer/index.html @@ -9,9 +9,8 @@ content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://steamcdn-a.akamaihd.net https://cdn.cloudflare.steamstatic.com https://cdn2.steamgriddb.com https://cdn.akamai.steamstatic.com;" /> - +
-

hello

diff --git a/src/renderer/src/components/bottom-panel/bottom-panel.tsx b/src/renderer/src/components/bottom-panel/bottom-panel.tsx index ed9a54ed..993d6aa5 100644 --- a/src/renderer/src/components/bottom-panel/bottom-panel.tsx +++ b/src/renderer/src/components/bottom-panel/bottom-panel.tsx @@ -22,7 +22,7 @@ export function BottomPanel() { }, []); const status = useMemo(() => { - if (isDownloading) { + if (isDownloading && game) { if (game.status === "downloading_metadata") return t("downloading_metadata", { title: game.title }); diff --git a/src/renderer/src/components/modal/modal.tsx b/src/renderer/src/components/modal/modal.tsx index 9b5f8cf5..1f07e7d7 100644 --- a/src/renderer/src/components/modal/modal.tsx +++ b/src/renderer/src/components/modal/modal.tsx @@ -62,12 +62,14 @@ export function Modal({ const onMouseDown = (e: MouseEvent) => { if (!isTopMostModal()) return; - const clickedOutsideContent = !modalContentRef.current.contains( - e.target as Node - ); + if (modalContentRef.current) { + const clickedOutsideContent = modalContentRef.current.contains( + e.target as Node + ); - if (clickedOutsideContent) { - handleCloseClick(); + if (clickedOutsideContent) { + handleCloseClick(); + } } }; diff --git a/src/renderer/src/declaration.d.ts b/src/renderer/src/declaration.d.ts index 1d198ea5..a478f687 100644 --- a/src/renderer/src/declaration.d.ts +++ b/src/renderer/src/declaration.d.ts @@ -62,7 +62,7 @@ declare global { openGameInstaller: (gameId: number) => Promise; openGame: (gameId: number, executablePath: string) => Promise; closeGame: (gameId: number) => Promise; - removeGame: (gameId: number) => Promise; + removeGameFromLibrary: (gameId: number) => Promise; deleteGameFolder: (gameId: number) => Promise; getGameByObjectID: (objectID: string) => Promise; onPlaytime: (cb: (gameId: number) => void) => () => Electron.IpcRenderer; diff --git a/src/renderer/src/features/use-preferences-slice.ts b/src/renderer/src/features/use-preferences-slice.ts index f6a3cf65..d735e7a2 100644 --- a/src/renderer/src/features/use-preferences-slice.ts +++ b/src/renderer/src/features/use-preferences-slice.ts @@ -14,7 +14,10 @@ export const userPreferencesSlice = createSlice({ name: "userPreferences", initialState, reducers: { - setUserPreferences: (state, action: PayloadAction) => { + setUserPreferences: ( + state, + action: PayloadAction + ) => { state.value = action.payload; }, }, diff --git a/src/renderer/src/hooks/use-download.ts b/src/renderer/src/hooks/use-download.ts index 27f90e8d..44392242 100644 --- a/src/renderer/src/hooks/use-download.ts +++ b/src/renderer/src/hooks/use-download.ts @@ -58,17 +58,17 @@ export function useDownload() { deleteGame(gameId); }); - const removeGame = (gameId: number) => - window.electron.removeGame(gameId).then(() => { + const removeGameFromLibrary = (gameId: number) => + window.electron.removeGameFromLibrary(gameId).then(() => { updateLibrary(); }); const isVerifying = ["downloading_metadata", "checking_files"].includes( - lastPacket?.game.status + lastPacket?.game.status ?? "" ); const getETA = () => { - if (isVerifying || !isFinite(lastPacket?.timeRemaining)) { + if (isVerifying || !isFinite(lastPacket?.timeRemaining ?? 0)) { return ""; } @@ -124,7 +124,7 @@ export function useDownload() { pauseDownload, resumeDownload, cancelDownload, - removeGame, + removeGameFromLibrary, deleteGame, isGameDeleting, clearDownload: () => dispatch(clearDownload()), diff --git a/src/renderer/src/pages/downloads/downloads.tsx b/src/renderer/src/pages/downloads/downloads.tsx index aecf7b5e..ca9903a3 100644 --- a/src/renderer/src/pages/downloads/downloads.tsx +++ b/src/renderer/src/pages/downloads/downloads.tsx @@ -33,6 +33,7 @@ export function Downloads() { numSeeds, pauseDownload, resumeDownload, + removeGameFromLibrary, cancelDownload, deleteGame, isGameDeleting, @@ -52,11 +53,6 @@ export function Downloads() { updateLibrary(); }); - const removeGame = (gameId: number) => - window.electron.removeGame(gameId).then(() => { - updateLibrary(); - }); - const getFinalDownloadSize = (game: Game) => { const isGameDownloading = isDownloading && gameDownloading?.id === game?.id; @@ -194,7 +190,7 @@ export function Downloads() {
From 5e1c850c729c848137257f484a60d96e6e987c01 Mon Sep 17 00:00:00 2001 From: Hydra Date: Tue, 30 Apr 2024 03:59:35 +0100 Subject: [PATCH 136/140] chore: merge with main --- package.json | 4 +- src/locales/hu/translation.json | 294 +++++++++--------- src/locales/pt/translation.json | 2 +- src/renderer/src/components/hero/hero.css.ts | 5 - src/renderer/src/components/modal/modal.tsx | 54 ++-- .../src/components/text-field/text-field.tsx | 2 +- .../src/pages/game-details/game-details.tsx | 26 +- 7 files changed, 194 insertions(+), 193 deletions(-) diff --git a/package.json b/package.json index f2d341ba..0d3a1e65 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,10 @@ { "name": "hydra", - "version": "1.0.0", + "version": "1.1.1", "description": "Hydra", "main": "./out/main/index.js", "author": "Los Broxas", - "homepage": "https://electron-vite.org", + "homepage": "https://hydralauncher.site", "repository": { "type": "git", "url": "https://github.com/hydralauncher/hydra.git" diff --git a/src/locales/hu/translation.json b/src/locales/hu/translation.json index 087068ac..901574a1 100644 --- a/src/locales/hu/translation.json +++ b/src/locales/hu/translation.json @@ -1,147 +1,147 @@ -{ - "home": { - "featured": "Featured", - "recently_added": "Nemrég hozzáadott", - "trending": "Népszerű", - "surprise_me": "Lepj meg", - "no_results": "Nem található" - }, - "sidebar": { - "catalogue": "Katalógus", - "downloads": "Letöltések", - "settings": "Beállítások", - "my_library": "Könyvtáram", - "downloading_metadata": "{{title}} (Metadata letöltése…)", - "checking_files": "{{title}} ({{percentage}} - Fájlok ellenőrzése…)", - "paused": "{{title}} (Szünet)", - "downloading": "{{title}} ({{percentage}} - Letöltés…)", - "filter": "Könyvtár szűrése", - "follow_us": "Kövess minket", - "home": "Főoldal" - }, - "header": { - "search": "Keresés", - "home": "Főoldal", - "catalogue": "Katalógus", - "downloads": "Letöltések", - "search_results": "Keresési eredmények", - "settings": "Beállítások" - }, - "bottom_panel": { - "no_downloads_in_progress": "Nincsenek folyamatban lévő letöltések", - "downloading_metadata": "{{title}} metaadatainak letöltése…", - "checking_files": "{{title}} fájlok ellenőrzése… ({{percentage}} kész)", - "downloading": "{{title}} letöltése… ({{percentage}} kész) - Befejezés {{eta}} - {{speed}}" - }, - "catalogue": { - "next_page": "Következő olda", - "previous_page": "Előző olda" - }, - "game_details": { - "open_download_options": "Letöltési lehetőségek", - "download_options_zero": "Nincs letöltési lehetőség", - "download_options_one": "{{count}} letöltési lehetőség", - "download_options_other": "{{count}} letöltési lehetőség", - "updated_at": "Frissítve: {{updated_at}}", - "install": "Letöltés", - "resume": "Folytatás", - "pause": "Szüneteltetés", - "cancel": "Mégse", - "remove": "Eltávolítás", - "remove_from_list": "Eltávolítás", - "space_left_on_disk": "{{space}} szabad hely a lemezen", - "eta": "Befejezés {{eta}}", - "downloading_metadata": "Metaadatok letöltése…", - "checking_files": "Fájlok ellenőrzése…", - "filter": "Repackek szűrése", - "requirements": "Rendszerkövetelmények", - "minimum": "Minimális", - "recommended": "Ajánlott", - "no_minimum_requirements": "{{title}} nem tartalmaz információt a minimális követelményekről", - "no_recommended_requirements": "{{title}} nem tartalmaz információt az ajánlott követelményekről", - "paused_progress": "{{progress}} (Szünetel)", - "release_date": "Megjelenés: {{date}}", - "publisher": "Kiadta: {{publisher}}", - "copy_link_to_clipboard": "Link másolása", - "copied_link_to_clipboard": "Link másolva", - "hours": "óra", - "minutes": "perc", - "accuracy": "{{accuracy}}% pontosság", - "add_to_library": "Hozzáadás a könyvtárhoz", - "remove_from_library": "Eltávolítás a könyvtárból", - "no_downloads": "Nincs elérhető letöltés", - "play_time": "Játszva: {{amount}}", - "last_time_played": "Utoljára játszva {{period}}", - "not_played_yet": "{{title}} még nem játszottál", - "next_suggestion": "Következő javaslat", - "play": "Játék", - "deleting": "Telepítő törlése…", - "close": "Bezárás", - "playing_now": "Jelenleg játszva", - "change": "Változtatás", - "repacks_modal_description": "Choose the repack you want to download", - "downloads_path": "Letöltések helye", - "select_folder_hint": "Ahhoz, hogy megváltoztasd a helyet, hozzákell férned a", - "hydra_settings": "Hydra beállítások", - "download_now": "Töltsd le most" - }, - "activation": { - "title": "Hydra Aktiválása", - "installation_id": "Telepítési ID:", - "enter_activation_code": "Add meg az aktiválási kódodat", - "message": "Ha nem tudod, hol kérdezd meg ezt, akkor nem is kellene, hogy legyen ilyened.", - "activate": "Aktiválás", - "loading": "Betöltés…" - }, - "downloads": { - "resume": "Folytatás", - "pause": "Szüneteltetés", - "eta": "Befejezés {{eta}}", - "paused": "Szüneteltetve", - "verifying": "Ellenőrzés…", - "completed_at": "Befejezve {{date}}-kor", - "completed": "Befejezve", - "cancelled": "Megszakítva", - "download_again": "Újra letöltés", - "cancel": "Mégse", - "filter": "Letöltött játékok szűrése", - "remove": "Eltávolítás", - "downloading_metadata": "Metaadatok letöltése…", - "checking_files": "Fájlok ellenőrzése…", - "starting_download": "Letöltés indítása…", - "deleting": "Telepítő törlése…", - "delete": "Telepítő eltávolítása", - "remove_from_list": "Eltávolítás", - "delete_modal_title": "Biztos vagy benne?", - "delete_modal_description": "Ez eltávolít minden telepítési fájlt a számítógépedről", - "install": "Telepítés" - }, - "settings": { - "downloads_path": "Letöltések helye", - "change": "Frissítés", - "notifications": "Értesítések", - "enable_download_notifications": "Amikor egy letöltés befejeződik", - "enable_repack_list_notifications": "Amikor egy új repack hozzáadásra kerül", - "telemetry": "Telemetria", - "telemetry_description": "Névtelen felhasználási statisztikák engedélyezése" - }, - "notifications": { - "download_complete": "Letöltés befejeződött", - "game_ready_to_install": "{{title}} telepítésre kész", - "repack_list_updated": "Repack lista frissítve", - "repack_count_one": "{{count}} repack hozzáadva", - "repack_count_other": "{{count}} repack hozzáadva" - }, - "system_tray": { - "open": "Hydra megnyitása", - "quit": "Kilépés" - }, - "game_card": { - "no_downloads": "Nincs elérhető letöltés" - }, - "binary_not_found_modal": { - "title": "A programok nincsenek telepítve", - "description": "A Wine vagy a Lutris végrehajtható fájljai nem találhatók a rendszereden", - "instructions": "Ellenőrizd a megfelelő telepítési módot bármelyiküknek a Linux disztribúciódon, hogy a játék normálisan fusson" - } -} +{ + "home": { + "featured": "Featured", + "recently_added": "Nemrég hozzáadott", + "trending": "Népszerű", + "surprise_me": "Lepj meg", + "no_results": "Nem található" + }, + "sidebar": { + "catalogue": "Katalógus", + "downloads": "Letöltések", + "settings": "Beállítások", + "my_library": "Könyvtáram", + "downloading_metadata": "{{title}} (Metadata letöltése…)", + "checking_files": "{{title}} ({{percentage}} - Fájlok ellenőrzése…)", + "paused": "{{title}} (Szünet)", + "downloading": "{{title}} ({{percentage}} - Letöltés…)", + "filter": "Könyvtár szűrése", + "follow_us": "Kövess minket", + "home": "Főoldal" + }, + "header": { + "search": "Keresés", + "home": "Főoldal", + "catalogue": "Katalógus", + "downloads": "Letöltések", + "search_results": "Keresési eredmények", + "settings": "Beállítások" + }, + "bottom_panel": { + "no_downloads_in_progress": "Nincsenek folyamatban lévő letöltések", + "downloading_metadata": "{{title}} metaadatainak letöltése…", + "checking_files": "{{title}} fájlok ellenőrzése… ({{percentage}} kész)", + "downloading": "{{title}} letöltése… ({{percentage}} kész) - Befejezés {{eta}} - {{speed}}" + }, + "catalogue": { + "next_page": "Következő olda", + "previous_page": "Előző olda" + }, + "game_details": { + "open_download_options": "Letöltési lehetőségek", + "download_options_zero": "Nincs letöltési lehetőség", + "download_options_one": "{{count}} letöltési lehetőség", + "download_options_other": "{{count}} letöltési lehetőség", + "updated_at": "Frissítve: {{updated_at}}", + "install": "Letöltés", + "resume": "Folytatás", + "pause": "Szüneteltetés", + "cancel": "Mégse", + "remove": "Eltávolítás", + "remove_from_list": "Eltávolítás", + "space_left_on_disk": "{{space}} szabad hely a lemezen", + "eta": "Befejezés {{eta}}", + "downloading_metadata": "Metaadatok letöltése…", + "checking_files": "Fájlok ellenőrzése…", + "filter": "Repackek szűrése", + "requirements": "Rendszerkövetelmények", + "minimum": "Minimális", + "recommended": "Ajánlott", + "no_minimum_requirements": "{{title}} nem tartalmaz információt a minimális követelményekről", + "no_recommended_requirements": "{{title}} nem tartalmaz információt az ajánlott követelményekről", + "paused_progress": "{{progress}} (Szünetel)", + "release_date": "Megjelenés: {{date}}", + "publisher": "Kiadta: {{publisher}}", + "copy_link_to_clipboard": "Link másolása", + "copied_link_to_clipboard": "Link másolva", + "hours": "óra", + "minutes": "perc", + "accuracy": "{{accuracy}}% pontosság", + "add_to_library": "Hozzáadás a könyvtárhoz", + "remove_from_library": "Eltávolítás a könyvtárból", + "no_downloads": "Nincs elérhető letöltés", + "play_time": "Játszva: {{amount}}", + "last_time_played": "Utoljára játszva {{period}}", + "not_played_yet": "{{title}} még nem játszottál", + "next_suggestion": "Következő javaslat", + "play": "Játék", + "deleting": "Telepítő törlése…", + "close": "Bezárás", + "playing_now": "Jelenleg játszva", + "change": "Változtatás", + "repacks_modal_description": "Choose the repack you want to download", + "downloads_path": "Letöltések helye", + "select_folder_hint": "Ahhoz, hogy megváltoztasd a helyet, hozzákell férned a", + "hydra_settings": "Hydra beállítások", + "download_now": "Töltsd le most" + }, + "activation": { + "title": "Hydra Aktiválása", + "installation_id": "Telepítési ID:", + "enter_activation_code": "Add meg az aktiválási kódodat", + "message": "Ha nem tudod, hol kérdezd meg ezt, akkor nem is kellene, hogy legyen ilyened.", + "activate": "Aktiválás", + "loading": "Betöltés…" + }, + "downloads": { + "resume": "Folytatás", + "pause": "Szüneteltetés", + "eta": "Befejezés {{eta}}", + "paused": "Szüneteltetve", + "verifying": "Ellenőrzés…", + "completed_at": "Befejezve {{date}}-kor", + "completed": "Befejezve", + "cancelled": "Megszakítva", + "download_again": "Újra letöltés", + "cancel": "Mégse", + "filter": "Letöltött játékok szűrése", + "remove": "Eltávolítás", + "downloading_metadata": "Metaadatok letöltése…", + "checking_files": "Fájlok ellenőrzése…", + "starting_download": "Letöltés indítása…", + "deleting": "Telepítő törlése…", + "delete": "Telepítő eltávolítása", + "remove_from_list": "Eltávolítás", + "delete_modal_title": "Biztos vagy benne?", + "delete_modal_description": "Ez eltávolít minden telepítési fájlt a számítógépedről", + "install": "Telepítés" + }, + "settings": { + "downloads_path": "Letöltések helye", + "change": "Frissítés", + "notifications": "Értesítések", + "enable_download_notifications": "Amikor egy letöltés befejeződik", + "enable_repack_list_notifications": "Amikor egy új repack hozzáadásra kerül", + "telemetry": "Telemetria", + "telemetry_description": "Névtelen felhasználási statisztikák engedélyezése" + }, + "notifications": { + "download_complete": "Letöltés befejeződött", + "game_ready_to_install": "{{title}} telepítésre kész", + "repack_list_updated": "Repack lista frissítve", + "repack_count_one": "{{count}} repack hozzáadva", + "repack_count_other": "{{count}} repack hozzáadva" + }, + "system_tray": { + "open": "Hydra megnyitása", + "quit": "Kilépés" + }, + "game_card": { + "no_downloads": "Nincs elérhető letöltés" + }, + "binary_not_found_modal": { + "title": "A programok nincsenek telepítve", + "description": "A Wine vagy a Lutris végrehajtható fájljai nem találhatók a rendszereden", + "instructions": "Ellenőrizd a megfelelő telepítési módot bármelyiküknek a Linux disztribúciódon, hogy a játék normálisan fusson" + } +} diff --git a/src/locales/pt/translation.json b/src/locales/pt/translation.json index c6b393bb..270e0451 100644 --- a/src/locales/pt/translation.json +++ b/src/locales/pt/translation.json @@ -3,7 +3,7 @@ "featured": "Destaque", "recently_added": "Novidades", "trending": "Populares", - "surprise_me": "Me surpreenda", + "surprise_me": "Surpreenda-me", "no_results": "Nenhum resultado encontrado" }, "sidebar": { diff --git a/src/renderer/src/components/hero/hero.css.ts b/src/renderer/src/components/hero/hero.css.ts index cc4aea7a..3c9ec81c 100644 --- a/src/renderer/src/components/hero/hero.css.ts +++ b/src/renderer/src/components/hero/hero.css.ts @@ -13,11 +13,6 @@ export const hero = style({ cursor: "pointer", border: `solid 1px ${vars.color.borderColor}`, zIndex: "1", - "@media": { - "(min-width: 1250px)": { - backgroundPosition: "center", - }, - }, }); export const heroMedia = style({ diff --git a/src/renderer/src/components/modal/modal.tsx b/src/renderer/src/components/modal/modal.tsx index 1f07e7d7..b8b4e7ef 100644 --- a/src/renderer/src/components/modal/modal.tsx +++ b/src/renderer/src/components/modal/modal.tsx @@ -41,6 +41,7 @@ export function Modal({ const isTopMostModal = () => { const openModals = document.querySelectorAll("[role=modal]"); + return ( openModals.length && openModals[openModals.length - 1] === modalContentRef.current @@ -48,34 +49,37 @@ export function Modal({ }; useEffect(() => { - const onKeyDown = (e: KeyboardEvent) => { - if (e.key === "Escape" && isTopMostModal()) { - handleCloseClick(); - } - }; - - window.addEventListener("keydown", onKeyDown); - return () => window.removeEventListener("keydown", onKeyDown); - }, [handleCloseClick]); - - useEffect(() => { - const onMouseDown = (e: MouseEvent) => { - if (!isTopMostModal()) return; - - if (modalContentRef.current) { - const clickedOutsideContent = modalContentRef.current.contains( - e.target as Node - ); - - if (clickedOutsideContent) { + if (visible) { + const onKeyDown = (e: KeyboardEvent) => { + if (e.key === "Escape" && isTopMostModal()) { handleCloseClick(); } - } - }; + }; - window.addEventListener("mousedown", onMouseDown); - return () => window.removeEventListener("mousedown", onMouseDown); - }, [handleCloseClick]); + const onMouseDown = (e: MouseEvent) => { + if (!isTopMostModal()) return; + if (modalContentRef.current) { + const clickedWithinModal = modalContentRef.current.contains( + e.target as Node + ); + + if (!clickedWithinModal) { + handleCloseClick(); + } + } + }; + + window.addEventListener("keydown", onKeyDown); + window.addEventListener("mousedown", onMouseDown); + + return () => { + window.removeEventListener("keydown", onKeyDown); + window.removeEventListener("mousedown", onMouseDown); + }; + } + + return () => {}; + }, [handleCloseClick, visible]); useEffect(() => { dispatch(toggleDragging(visible)); diff --git a/src/renderer/src/components/text-field/text-field.tsx b/src/renderer/src/components/text-field/text-field.tsx index 62378615..3b86e290 100644 --- a/src/renderer/src/components/text-field/text-field.tsx +++ b/src/renderer/src/components/text-field/text-field.tsx @@ -7,7 +7,7 @@ export interface TextFieldProps React.InputHTMLAttributes, HTMLInputElement > { - theme?: RecipeVariants["theme"]; + theme?: NonNullable>["theme"]; label?: string; } diff --git a/src/renderer/src/pages/game-details/game-details.tsx b/src/renderer/src/pages/game-details/game-details.tsx index c6b2daa0..59b25ba9 100644 --- a/src/renderer/src/pages/game-details/game-details.tsx +++ b/src/renderer/src/pages/game-details/game-details.tsx @@ -137,17 +137,19 @@ export function GameDetails() { repackId: number, downloadPath: string ) => { - return startDownload( - repackId, - gameDetails.objectID, - gameDetails.name, - shop as GameShop, - downloadPath - ).then(() => { - getGame(); - setShowRepacksModal(false); - setShowSelectFolderModal(false); - }); + if (gameDetails) { + return startDownload( + repackId, + gameDetails.objectID, + gameDetails.name, + shop as GameShop, + downloadPath + ).then(() => { + getGame(); + setShowRepacksModal(false); + setShowSelectFolderModal(false); + }); + } }; const handleRandomizerClick = async () => { @@ -261,7 +263,7 @@ export function GameDetails() { title: gameDetails?.name, }), }} - >
+ />
From d85fa66a877d18cf4c6065d1f43a6b1974303c2f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 30 Apr 2024 03:15:11 +0000 Subject: [PATCH 137/140] docs(contributor): contrib-readme-action has updated readme --- README.md | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/README.md b/README.md index 981a8707..ea6256e6 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,87 @@ yarn make ## Contributors + + + + + + + + + + + + + + +
+ + hydralauncher +
+ Hydra +
+
+ + zamitto +
+ Null +
+
+ + fzanutto +
+ Null +
+
+ + JackEnx +
+ Null +
+
+ + fhilipecrash +
+ Fhilipe Coelho +
+
+ + Magrid0 +
+ Magrid +
+
+ + ferivoq +
+ FeriVOQ +
+
+ + xbozo +
+ Guilherme Viana +
+
+ + pmenta +
+ João Martins +
+
+ + eltociear +
+ Ikko Eltociear Ashimine +
+
+ + Netflixyapp +
+ Netflixy +
+
## License From 06d334d2d70f31671f762077891c1223ef7096cd Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 30 Apr 2024 03:15:11 +0000 Subject: [PATCH 138/140] docs(contributor): contrib-readme-action has updated readme --- README.md | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/README.md b/README.md index 981a8707..ea6256e6 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,87 @@ yarn make ## Contributors + + + + + + + + + + + + + + +
+ + hydralauncher +
+ Hydra +
+
+ + zamitto +
+ Null +
+
+ + fzanutto +
+ Null +
+
+ + JackEnx +
+ Null +
+
+ + fhilipecrash +
+ Fhilipe Coelho +
+
+ + Magrid0 +
+ Magrid +
+
+ + ferivoq +
+ FeriVOQ +
+
+ + xbozo +
+ Guilherme Viana +
+
+ + pmenta +
+ João Martins +
+
+ + eltociear +
+ Ikko Eltociear Ashimine +
+
+ + Netflixyapp +
+ Netflixy +
+
## License From 15ba37915248d7c1a451a56d56402a31ceb236dc Mon Sep 17 00:00:00 2001 From: Zamitto Date: Tue, 30 Apr 2024 16:04:42 -0300 Subject: [PATCH 139/140] fix: update fastlist directory --- .gitignore | 1 + electron-builder.yml | 1 + postinstall.cjs | 6 +----- src/main/helpers/ps.ts | 4 ++-- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 0767dd62..675a83ee 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .vscode node_modules hydra-download-manager +fastlist.exe __pycache__ dist out diff --git a/electron-builder.yml b/electron-builder.yml index 9101b028..9acb2eac 100644 --- a/electron-builder.yml +++ b/electron-builder.yml @@ -5,6 +5,7 @@ directories: extraResources: - hydra-download-manager - hydra.db + - fastlist.exe files: - "!**/.vscode/*" - "!src/*" diff --git a/postinstall.cjs b/postinstall.cjs index 0b47b380..8ca8f101 100644 --- a/postinstall.cjs +++ b/postinstall.cjs @@ -1,12 +1,8 @@ const fs = require("fs"); if (process.platform === "win32") { - if (!fs.existsSync("resources/dist")) { - fs.mkdirSync("resources/dist"); - } - fs.copyFileSync( "node_modules/ps-list/vendor/fastlist-0.3.0-x64.exe", - "resources/dist/fastlist.exe" + "fastlist.exe" ); } diff --git a/src/main/helpers/ps.ts b/src/main/helpers/ps.ts index dbc11f09..380b5116 100644 --- a/src/main/helpers/ps.ts +++ b/src/main/helpers/ps.ts @@ -10,8 +10,8 @@ const execFile = promisify(childProcess.execFile); export const getProcesses = async () => { if (process.platform == "win32") { const binaryPath = app.isPackaged - ? path.join(process.resourcesPath, "dist", "fastlist.exe") - : path.join(__dirname, "..", "..", "resources", "dist", "fastlist.exe"); + ? path.join(process.resourcesPath, "fastlist.exe") + : path.join(__dirname, "..", "..", "fastlist.exe"); const { stdout } = await execFile(binaryPath, { maxBuffer: TEN_MEGABYTES, From f14ddba8075f964fe318c11ed35f5f28f0d15445 Mon Sep 17 00:00:00 2001 From: Zamitto Date: Tue, 30 Apr 2024 16:04:42 -0300 Subject: [PATCH 140/140] fix: update fastlist directory --- .gitignore | 1 + electron-builder.yml | 1 + postinstall.cjs | 6 +----- src/main/helpers/ps.ts | 4 ++-- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 0767dd62..675a83ee 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ .vscode node_modules hydra-download-manager +fastlist.exe __pycache__ dist out diff --git a/electron-builder.yml b/electron-builder.yml index 9101b028..9acb2eac 100644 --- a/electron-builder.yml +++ b/electron-builder.yml @@ -5,6 +5,7 @@ directories: extraResources: - hydra-download-manager - hydra.db + - fastlist.exe files: - "!**/.vscode/*" - "!src/*" diff --git a/postinstall.cjs b/postinstall.cjs index 0b47b380..8ca8f101 100644 --- a/postinstall.cjs +++ b/postinstall.cjs @@ -1,12 +1,8 @@ const fs = require("fs"); if (process.platform === "win32") { - if (!fs.existsSync("resources/dist")) { - fs.mkdirSync("resources/dist"); - } - fs.copyFileSync( "node_modules/ps-list/vendor/fastlist-0.3.0-x64.exe", - "resources/dist/fastlist.exe" + "fastlist.exe" ); } diff --git a/src/main/helpers/ps.ts b/src/main/helpers/ps.ts index dbc11f09..380b5116 100644 --- a/src/main/helpers/ps.ts +++ b/src/main/helpers/ps.ts @@ -10,8 +10,8 @@ const execFile = promisify(childProcess.execFile); export const getProcesses = async () => { if (process.platform == "win32") { const binaryPath = app.isPackaged - ? path.join(process.resourcesPath, "dist", "fastlist.exe") - : path.join(__dirname, "..", "..", "resources", "dist", "fastlist.exe"); + ? path.join(process.resourcesPath, "fastlist.exe") + : path.join(__dirname, "..", "..", "fastlist.exe"); const { stdout } = await execFile(binaryPath, { maxBuffer: TEN_MEGABYTES,