[Linux-only] basically bloxstap for sober
1import { $ } from "bun";
2import { writeFileSync } from "fs";
3import { homedir } from "os";
4import { join } from "path";
5import { isCompiled } from "../constants";
6
7type DesktopEntry = {
8 name: string;
9 genericName: string;
10 comment: string;
11 keywords?: string[];
12 executable: string;
13 type: "Application";
14 noDisplay: boolean;
15 categories: string[];
16 icon?: string;
17 mimeTypes: string[];
18};
19
20/** tuxstrap.desktop */
21export const tuxstrapDesktopEntry: DesktopEntry = {
22 name: "TuxStrap",
23 genericName: "Roblox Player",
24 comment: "Basically just Bloxstrap, but for Linux!",
25 keywords: [
26 "roblox",
27 "vinegar",
28 "game",
29 "gaming",
30 "social",
31 "experience",
32 "launcher"
33 ],
34 type: "Application",
35 noDisplay: false,
36 icon: "org.vinegarhq.Sober",
37 mimeTypes: ["x-scheme-handler/roblox", "x-scheme-handler/roblox-player"],
38 categories: ["GNOME", "GTK", "Game"],
39 executable: `${process.argv.filter((a) => !a.includes("roblox")).join(" ")} -- @@u %u @@`
40};
41
42export function createDesktopEntry(d: DesktopEntry, realPath?: string) {
43 return `[Desktop Entry]
44 Type=${d.type}
45 Name=${d.name}
46 GenericName=${d.genericName}
47 Comment=${d.comment}
48 ${d.keywords && `Keywords=${d.keywords.join(";")};`}
49 ${d.icon && `Icon=${d.icon}`}
50 NoDisplay=${d.noDisplay}
51 Categories=${d.categories.join(";")};
52 Exec=${realPath ? realPath + " -- @@u %u @@" : d.executable}
53 MimeType=${d.mimeTypes.join(";")};
54 `
55 .replace(/^\t+/gm, "")
56 .replaceAll("\n\n", "\n");
57}
58
59export async function registerXDG(fileName: string) {
60 if (
61 isCompiled
62 ) {
63 for (const mimeType of tuxstrapDesktopEntry.mimeTypes) {
64 const r = await $`xdg-mime default ${fileName} ${mimeType}`
65 .nothrow()
66 .quiet();
67 if (r.exitCode === 0) {
68 console.log(
69 `Registered Default XDG Mime ${mimeType} -> ${fileName}`
70 );
71 } else {
72 console.error(
73 `Failed to Register Default XDG Mime ${mimeType} -> ${fileName} (Exit code ${r.exitCode})`
74 );
75 }
76 }
77 return;
78 }
79 const desktopEntry = createDesktopEntry(tuxstrapDesktopEntry);
80 const dir = join(homedir(), ".local", "share", "applications");
81 try {
82 writeFileSync(join(dir, fileName), desktopEntry);
83 console.log(`Placed ${fileName} in ${dir}`);
84 for (const mimeType of tuxstrapDesktopEntry.mimeTypes) {
85 const r = await $`xdg-mime default ${fileName} ${mimeType}`
86 .nothrow()
87 .quiet();
88 if (r.exitCode === 0) {
89 console.log(
90 `Registered Default XDG Mime ${mimeType} -> ${fileName}`
91 );
92 } else {
93 console.error(
94 `Failed to Register Default XDG Mime ${mimeType} -> ${fileName} (Exit code ${r.exitCode})`
95 );
96 }
97 }
98 } catch {}
99}