brave-rofi-menu
Version:
A tool to switch Brave browser tabs using i3 and rofi.
168 lines (147 loc) • 6.06 kB
JavaScript
import { createRequire } from 'module'; // Import createRequire for compatibility
const require = createRequire(import.meta.url); // Create a require function
import CDP from 'chrome-remote-interface';
import { execSync } from 'child_process';
async function findAndFocusBraveWindow(tabTitle) {
try {
console.log('Searching for Brave windows...');
// Get a list of all i3 windows
const i3Windows = JSON.parse(execSync('i3-msg -t get_tree').toString());
// Recursively find Brave windows
const findBraveWindows = (node, braveWindows = []) => {
if (node.nodes) {
for (const child of node.nodes) {
findBraveWindows(child, braveWindows);
}
}
if (node.window && node.name && node.name.includes('Brave')) {
braveWindows.push({ id: node.window, name: node.name });
}
return braveWindows;
};
const braveWindows = findBraveWindows(i3Windows);
if (braveWindows.length > 0) {
// Find the Brave window matching the tab title
const targetWindow = braveWindows.find((win) => win.name.includes(tabTitle));
if (targetWindow) {
execSync(`i3-msg [id="${targetWindow.id}"] focus`);
console.log(`Focused on Brave window: ${targetWindow.name}`);
} else {
console.warn(`Tab title "${tabTitle}" not found. Focusing the first Brave window.`);
execSync(`i3-msg [id="${braveWindows[0].id}"] focus`);
}
} else {
throw new Error('No Brave windows found in i3.');
}
} catch (err) {
if (err instanceof SyntaxError) {
console.error('JSON parse error while fetching i3 windows:', err.message);
} else {
console.error('Unexpected error focusing Brave window:', err.message);
}
}
}
export async function braveRofiMenu() {
try {
console.log('Connecting to Brave...');
const client = await CDP({
host: 'localhost',
port: 9222,
});
console.log('Connected to Brave.');
// Get the list of all targets
const targets = await CDP.List({
host: 'localhost',
port: 9222,
});
// Filter for page type targets
const pages = targets.filter((target) => target.type === 'page');
if (pages.length === 0) {
throw new Error('No pages found. Ensure Brave is running with open tabs.');
}
console.log(`Found ${pages.length} page(s):`);
pages.forEach((page, index) => {
console.log(` ${index + 1}. ${page.title || 'Untitled'} - ${page.url}`);
});
// Display options in rofi with separators
const pageOptions = pages
.map((page, index) => `${index + 1}. ${page.title || 'Untitled'} - ${page.url}`)
.join('\n');
const selected = execSync(
`echo -e "Search (Brave)\n────\n${pageOptions}\n────\n- Bookmarks\n- New Tab\n- Close Tab\n- Search in incognito\n- Exit" | rofi -dmenu -i -p "Select Tab" -theme-str 'window { fullscreen: true; } mainbox { padding: 2%; }'`
)
.toString()
.trim();
if (selected === 'Search (Brave)') {
const searchQuery = execSync(
`rofi -dmenu -p "Enter search query:" -theme-str 'window { fullscreen: true; } mainbox { padding: 2%; }'`
)
.toString()
.trim();
if (searchQuery) {
console.log(`Searching for: ${searchQuery}`);
const { Target } = client;
const searchUrl = `https://search.brave.com/search?q=${encodeURIComponent(searchQuery)}`;
const newTarget = await Target.createTarget({ url: searchUrl });
console.log('Opened search result in new tab:', newTarget);
// Focus on the Brave browser window
await findAndFocusBraveWindow(searchQuery);
} else {
console.log('Search query is empty. No action taken.');
}
} else if (selected === '- Bookmarks') {
console.log('Launching bookmarks script...');
execSync('~/bin/rofi/rofi-bookmarks-brave');
console.log('Bookmarks script launched.');
} else if (selected === '- New Tab') {
console.log('Opening new tab...');
const { Target } = client;
const newTarget = await Target.createTarget({ url: 'brave://newtab' });
console.log('New tab opened:', newTarget);
} else if (selected === '- Close Tab') {
const tabsToClose = execSync(
`echo -e "${pageOptions}" | rofi -dmenu -i -p "Select Tabs to Close" -multi-select -theme-str 'window { fullscreen: true; } mainbox { padding: 2%; }'`
)
.toString()
.trim()
.split('\n');
if (tabsToClose.length > 0) {
const { Target } = client;
for (const tab of tabsToClose) {
const selectedIndex = parseInt(tab.split('.')[0]) - 1;
if (!isNaN(selectedIndex)) {
const selectedPage = pages[selectedIndex];
await Target.closeTarget({ targetId: selectedPage.id });
console.log(`Closed tab: ${selectedPage.title}`);
}
}
} else {
console.log('No tabs selected to close.');
}
} else if (selected === '- Search in incognito') {
console.log('Launching incognito search script...');
execSync('~/bin/rofi/rofi-brave-debug-incognito');
console.log('Incognito search script launched.');
} else if (selected === '- Exit' || !selected) {
console.log('Exiting...');
} else {
const selectedIndex = parseInt(selected.split('.')[0]) - 1;
if (!isNaN(selectedIndex)) {
console.log(`Switching to tab ${selectedIndex + 1}...`);
const selectedPage = pages[selectedIndex];
const { Target } = client;
await Target.activateTarget({ targetId: selectedPage.id });
console.log(`Switched to: ${selectedPage.title}`);
await findAndFocusBraveWindow(selectedPage.title);
}
}
await client.close();
console.log('Disconnected from Brave.');
} catch (err) {
console.error('Error:', err.message);
}
};
// Check if the module is being run directly
if (import.meta.url === `file://${process.argv[1]}`) {
braveRofiMenu();
}