mirror of
https://github.com/zhom/donutbrowser.git
synced 2026-08-02 17:28:43 +02:00
Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f1faa02e4 | ||
|
|
7a5b807828 | ||
|
|
d0a5c16ce9 | ||
|
|
e2e1ad1582 | ||
|
|
cb61861503 | ||
|
|
1950ef0098 | ||
|
|
814875c28e | ||
|
|
b06ca4f11e |
@@ -19,16 +19,3 @@ jobs:
|
|||||||
uses: dependabot/fetch-metadata@v2
|
uses: dependabot/fetch-metadata@v2
|
||||||
with:
|
with:
|
||||||
github-token: "${{ secrets.GITHUB_TOKEN }}"
|
github-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||||
|
|
||||||
- name: Approve Dependabot PR
|
|
||||||
run: gh pr review --approve "$PR_URL"
|
|
||||||
env:
|
|
||||||
PR_URL: ${{ github.event.pull_request.html_url }}
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Auto-merge (squash) Dependabot PR
|
|
||||||
if: ${{ steps.dependabot-metadata.outputs.update-type != 'version-update:semver-major' }}
|
|
||||||
run: gh pr merge --auto --squash "$PR_URL"
|
|
||||||
env:
|
|
||||||
PR_URL: ${{ github.event.pull_request.html_url }}
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|||||||
+2
-2
@@ -30,8 +30,8 @@ yarn-error.log*
|
|||||||
.pnpm-debug.log*
|
.pnpm-debug.log*
|
||||||
|
|
||||||
# nodecar
|
# nodecar
|
||||||
nodecar/dist
|
**/dist
|
||||||
nodecar/node_modules
|
**/node_modules
|
||||||
|
|
||||||
# local env files
|
# local env files
|
||||||
.env*.local
|
.env*.local
|
||||||
|
|||||||
@@ -54,6 +54,10 @@ Have questions or want to contribute? We'd love to hear from you!
|
|||||||
- **Issues**: [GitHub Issues](https://github.com/zhom/donutbrowser/issues)
|
- **Issues**: [GitHub Issues](https://github.com/zhom/donutbrowser/issues)
|
||||||
- **Discussions**: [GitHub Discussions](https://github.com/zhom/donutbrowser/discussions)
|
- **Discussions**: [GitHub Discussions](https://github.com/zhom/donutbrowser/discussions)
|
||||||
|
|
||||||
|
## Contact
|
||||||
|
|
||||||
|
Have an urgent question or want to report a security vulnerability? Send an email to contact at donutbrowser dot com and we'll get back to you as fast as possible.
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This project is licensed under the AGPL-3.0 License - see the [LICENSE](LICENSE) file for details.
|
This project is licensed under the AGPL-3.0 License - see the [LICENSE](LICENSE) file for details.
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "AGPL-3.0",
|
||||||
"packageManager": "pnpm@10.6.1",
|
"packageManager": "pnpm@10.6.1",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "^22.15.17",
|
"@types/node": "^22.15.17",
|
||||||
|
|||||||
+4
-3
@@ -1,7 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "donutbrowser",
|
"name": "donutbrowser",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.2.4",
|
"license": "AGPL-3.0",
|
||||||
|
"version": "0.2.5",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev --turbopack",
|
"dev": "next dev --turbopack",
|
||||||
@@ -36,7 +37,7 @@
|
|||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"cmdk": "^1.1.1",
|
"cmdk": "^1.1.1",
|
||||||
"next": "^15.3.2",
|
"next": "^15.3.3",
|
||||||
"next-themes": "^0.4.6",
|
"next-themes": "^0.4.6",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
@@ -61,7 +62,7 @@
|
|||||||
"eslint-config-next": "^15.3.2",
|
"eslint-config-next": "^15.3.2",
|
||||||
"eslint-plugin-react-hooks": "^5.2.0",
|
"eslint-plugin-react-hooks": "^5.2.0",
|
||||||
"husky": "^9.1.7",
|
"husky": "^9.1.7",
|
||||||
"lint-staged": "^15.3.0",
|
"lint-staged": "^16.1.0",
|
||||||
"tailwindcss": "^4.1.7",
|
"tailwindcss": "^4.1.7",
|
||||||
"tw-animate-css": "^1.3.0",
|
"tw-animate-css": "^1.3.0",
|
||||||
"typescript": "~5.8.3",
|
"typescript": "~5.8.3",
|
||||||
|
|||||||
Generated
+928
-942
File diff suppressed because it is too large
Load Diff
Generated
+1
-1
@@ -963,7 +963,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "donutbrowser"
|
name = "donutbrowser"
|
||||||
version = "0.2.4"
|
version = "0.2.5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"base64 0.22.1",
|
"base64 0.22.1",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "donutbrowser"
|
name = "donutbrowser"
|
||||||
version = "0.2.4"
|
version = "0.2.5"
|
||||||
description = "Browser Orchestrator"
|
description = "Browser Orchestrator"
|
||||||
authors = ["zhom@github"]
|
authors = ["zhom@github"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1</string>
|
<string>1</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>0.2.4</string>
|
<string>0.2.5</string>
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleIconFile</key>
|
<key>CFBundleIconFile</key>
|
||||||
|
|||||||
@@ -153,8 +153,8 @@ pub async fn open_url_with_profile(
|
|||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn smart_open_url(
|
pub async fn smart_open_url(
|
||||||
_app_handle: tauri::AppHandle,
|
app_handle: tauri::AppHandle,
|
||||||
_url: String,
|
url: String,
|
||||||
_is_startup: Option<bool>,
|
_is_startup: Option<bool>,
|
||||||
) -> Result<String, String> {
|
) -> Result<String, String> {
|
||||||
use crate::browser_runner::BrowserRunner;
|
use crate::browser_runner::BrowserRunner;
|
||||||
@@ -171,10 +171,75 @@ pub async fn smart_open_url(
|
|||||||
}
|
}
|
||||||
|
|
||||||
println!(
|
println!(
|
||||||
"URL opening - Total profiles: {}, showing profile selector",
|
"URL opening - Total profiles: {}, checking for running profiles",
|
||||||
profiles.len()
|
profiles.len()
|
||||||
);
|
);
|
||||||
|
|
||||||
// Always show the profile selector so the user can choose
|
// Check for running profiles and find the first one that can handle URLs
|
||||||
|
for profile in &profiles {
|
||||||
|
// Check if this profile is running
|
||||||
|
let is_running = runner
|
||||||
|
.check_browser_status(app_handle.clone(), profile)
|
||||||
|
.await
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
|
if is_running {
|
||||||
|
println!(
|
||||||
|
"Found running profile '{}', attempting to open URL",
|
||||||
|
profile.name
|
||||||
|
);
|
||||||
|
|
||||||
|
// For TOR browser: Check if any other TOR browser is running
|
||||||
|
if profile.browser == "tor-browser" {
|
||||||
|
let mut other_tor_running = false;
|
||||||
|
for p in &profiles {
|
||||||
|
if p.browser == "tor-browser"
|
||||||
|
&& p.name != profile.name
|
||||||
|
&& runner
|
||||||
|
.check_browser_status(app_handle.clone(), p)
|
||||||
|
.await
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
|
other_tor_running = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if other_tor_running {
|
||||||
|
continue; // Skip this one, can't have multiple TOR instances
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For Mullvad browser: skip if running (can't open URLs in running Mullvad)
|
||||||
|
if profile.browser == "mullvad-browser" {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to open the URL with this running profile
|
||||||
|
match runner
|
||||||
|
.launch_or_open_url(app_handle.clone(), profile, Some(url.clone()))
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => {
|
||||||
|
println!(
|
||||||
|
"Successfully opened URL '{}' with running profile '{}'",
|
||||||
|
url, profile.name
|
||||||
|
);
|
||||||
|
return Ok(format!("opened_with_profile:{}", profile.name));
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!(
|
||||||
|
"Failed to open URL with running profile '{}': {}",
|
||||||
|
profile.name, e
|
||||||
|
);
|
||||||
|
// Continue to try other profiles or show selector
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("No suitable running profiles found, showing profile selector");
|
||||||
|
|
||||||
|
// No suitable running profile found, show the profile selector
|
||||||
Err("show_selector".to_string())
|
Err("show_selector".to_string())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://schema.tauri.app/config/2",
|
"$schema": "https://schema.tauri.app/config/2",
|
||||||
"productName": "Donut Browser",
|
"productName": "Donut Browser",
|
||||||
"version": "0.2.4",
|
"version": "0.2.5",
|
||||||
"identifier": "com.donutbrowser",
|
"identifier": "com.donutbrowser",
|
||||||
"build": {
|
"build": {
|
||||||
"beforeDevCommand": "pnpm dev",
|
"beforeDevCommand": "pnpm dev",
|
||||||
|
|||||||
+4
-6
@@ -146,10 +146,7 @@ export default function Home() {
|
|||||||
// Listen for show profile selector events
|
// Listen for show profile selector events
|
||||||
await listen<string>("show-profile-selector", (event) => {
|
await listen<string>("show-profile-selector", (event) => {
|
||||||
console.log("Received show profile selector request:", event.payload);
|
console.log("Received show profile selector request:", event.payload);
|
||||||
setPendingUrls((prev) => [
|
setPendingUrls([{ id: Date.now().toString(), url: event.payload }]);
|
||||||
...prev,
|
|
||||||
{ id: Date.now().toString(), url: event.payload },
|
|
||||||
]);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Listen for show create profile dialog events
|
// Listen for show create profile dialog events
|
||||||
@@ -175,7 +172,7 @@ export default function Home() {
|
|||||||
url,
|
url,
|
||||||
});
|
});
|
||||||
console.log("Smart URL opening succeeded:", result);
|
console.log("Smart URL opening succeeded:", result);
|
||||||
// URL was handled successfully
|
// URL was handled successfully, no need to show selector
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
console.log(
|
console.log(
|
||||||
"Smart URL opening failed or requires profile selection:",
|
"Smart URL opening failed or requires profile selection:",
|
||||||
@@ -183,7 +180,8 @@ export default function Home() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Show profile selector for manual selection
|
// Show profile selector for manual selection
|
||||||
setPendingUrls((prev) => [...prev, { id: Date.now().toString(), url }]);
|
// Replace any existing pending URL with the new one
|
||||||
|
setPendingUrls([{ id: Date.now().toString(), url }]);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -69,16 +69,29 @@ export function ProfileSelectorDialog({
|
|||||||
|
|
||||||
// Auto-select first available profile for link opening
|
// Auto-select first available profile for link opening
|
||||||
if (profileList.length > 0) {
|
if (profileList.length > 0) {
|
||||||
// Find the first profile that can be used for opening links
|
// First, try to find a running profile that can be used for opening links
|
||||||
const availableProfile = profileList.find((profile) => {
|
const runningAvailableProfile = profileList.find((profile) => {
|
||||||
return canUseProfileForLinks(profile, profileList, runningProfiles);
|
const isRunning = runningProfiles.has(profile.name);
|
||||||
|
return (
|
||||||
|
isRunning &&
|
||||||
|
canUseProfileForLinks(profile, profileList, runningProfiles)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (availableProfile) {
|
if (runningAvailableProfile) {
|
||||||
setSelectedProfile(availableProfile.name);
|
setSelectedProfile(runningAvailableProfile.name);
|
||||||
} else {
|
} else {
|
||||||
// If no suitable profile found, still select the first one to show UI
|
// If no running profile is suitable, find the first profile that can be used for opening links
|
||||||
setSelectedProfile(profileList[0].name);
|
const availableProfile = profileList.find((profile) => {
|
||||||
|
return canUseProfileForLinks(profile, profileList, runningProfiles);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (availableProfile) {
|
||||||
|
setSelectedProfile(availableProfile.name);
|
||||||
|
} else {
|
||||||
|
// If no suitable profile found, still select the first one to show UI
|
||||||
|
setSelectedProfile(profileList[0].name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -277,7 +290,7 @@ export function ProfileSelectorDialog({
|
|||||||
!canUseForLinks ? "opacity-50" : ""
|
!canUseForLinks ? "opacity-50" : ""
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-3 p-3 rounded-lg hover:bg-accent cursor-pointer">
|
<div className="flex items-center gap-3 py-1 px-2 rounded-lg hover:bg-accent cursor-pointer">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{(() => {
|
{(() => {
|
||||||
const IconComponent = getBrowserIcon(
|
const IconComponent = getBrowserIcon(
|
||||||
|
|||||||
Reference in New Issue
Block a user