(getMainWindow)
| 178 | // ── IPC registration ────────────────────────────────────────────────────────── |
| 179 | |
| 180 | function register(getMainWindow) { |
| 181 | _getMainWindow = getMainWindow; |
| 182 | |
| 183 | // ── downloader binary detection ────────────────────────────────────────── |
| 184 | ipcMain.handle("check-downloader", (_, folderPath) => { |
| 185 | if (!folderPath) return { exists: false, reason: "no_folder" }; |
| 186 | let entries; |
| 187 | try { |
| 188 | entries = fs.readdirSync(folderPath); |
| 189 | } catch (e) { |
| 190 | const reason = |
| 191 | e.code === "EACCES" ? "folder_permission" : "folder_unreadable"; |
| 192 | return { exists: false, reason }; |
| 193 | } |
| 194 | if (!entries.includes("_internal")) { |
| 195 | return { exists: false, reason: "no_internal" }; |
| 196 | } |
| 197 | const binary = entries.find((e) => { |
| 198 | if (e === "_internal" || e.startsWith(".")) return false; |
| 199 | try { |
| 200 | const stat = fs.statSync(path.join(folderPath, e)); |
| 201 | if (!stat.isFile()) return false; |
| 202 | return process.platform === "win32" |
| 203 | ? e.endsWith(".exe") |
| 204 | : !!(stat.mode & 0o111); |
| 205 | } catch { |
| 206 | return false; |
| 207 | } |
| 208 | }); |
| 209 | if (!binary) return { exists: false, reason: "no_executable" }; |
| 210 | |
| 211 | // Store the validated path in the Main process only and hand a token to |
| 212 | // the Renderer. The Renderer passes the token back when starting a |
| 213 | // download; the real path is never exposed outside the Main process. |
| 214 | const token = crypto.randomUUID(); |
| 215 | trustedBinaryPaths.set(token, path.join(folderPath, binary)); |
| 216 | return { exists: true, token }; |
| 217 | }); |
| 218 | |
| 219 | // ── start download ──────────────────────────────────────────────────────── |
| 220 | ipcMain.handle( |
| 221 | "run-download", |
| 222 | ( |
| 223 | _, |
| 224 | { |
| 225 | token, |
| 226 | m3u8Url, |
| 227 | name, |
| 228 | downloadPath, |
| 229 | mediaId, |
| 230 | mediaType, |
| 231 | season, |
| 232 | episode, |
| 233 | posterPath, |
| 234 | tmdbId, |
| 235 | subtitles, |
| 236 | }, |
| 237 | ) => { |
nothing calls this directly
no test coverage detected