[Linux-only] basically bloxstap for sober
at dev 99 lines 2.5 kB view raw
1import { $ } from "bun"; 2import { GetProxyInterface, SendNotification } from "../api/linux"; 3import { registerPlugin } from "../api/Plugin"; 4import { getGameDetails } from "../api/roblox/GameInfo"; 5 6registerPlugin( 7 { 8 name: "System Clipboard & D-Bus", 9 id: "dbus", 10 description: "Let games control MPRIS music players with D-Bus and write to the Wayland clipboard", 11 forceEnable: true, 12 configPrio: -9e9 13 }, 14 async (plugin) => { 15 plugin.setFFlag("FFlagClientAllowClipboardControl", true); 16 plugin.setFFlag("FFlagClientAllowDBus", true); 17 plugin.setFFlag("FFlagIsLinux", true); 18 19 plugin.on("BLOXSTRAP_RPC", async (a) => { 20 switch (a.type) { 21 case "WaylandCopy": { 22 if (typeof a.data === "string" && a.data.length <= 512) { 23 } else { 24 return; 25 } 26 const gameName = await getGameDetails( 27 plugin.currentState.getPlaceId()! 28 ); 29 if (!gameName) return; 30 await SendNotification( 31 "Roblox", 32 `${gameName} wrote to the Wayland clipboard!`, 33 3000 34 ); 35 //TODO - fix this. https://roblox.com/games/15918403591 writes to clipboard, but it's not actually written 36 $`echo ${a.data} | wl-copy -n`.quiet().nothrow(); // <-- wayland is wayland (this is broken) 37 break; 38 } 39 case "CallDBus": { 40 if (typeof a.data !== "object") return; 41 if (typeof a.data.busName !== "string") return; 42 if (typeof a.data.action !== "string") return; 43 44 let { 45 busName, 46 action 47 }: { busName: string; action: string } = a.data; 48 49 if (busName.length >= 64) return; 50 if (!busName.startsWith("org.mpris.MediaPlayer2.")) 51 busName = "org.mpris.MediaPlayer2." + busName; 52 53 if ( 54 ![ 55 "Play", 56 "Pause", 57 "PlayPause", 58 "Previous", 59 "Next" 60 ].includes(action) 61 ) 62 return; 63 64 try { 65 const i = await GetProxyInterface( 66 busName, 67 "/org/mpris/MediaPlayer2", 68 "org.mpris.MediaPlayer2.Player" 69 ); 70 switch (action) { 71 case "Play": { 72 await (i as any).Play(); 73 break; 74 } 75 case "Pause": { 76 await (i as any).Pause(); 77 break; 78 } 79 case "PlayPause": { 80 await (i as any).PlayPause(); 81 break; 82 } 83 case "Previous": { 84 await (i as any).Previous(); 85 break; 86 } 87 case "Next": { 88 await (i as any).Next(); 89 break; 90 } 91 } 92 } catch {} 93 94 break; 95 } 96 } 97 }); 98 } 99);