BrowseRouter
BrowseRouter copied to clipboard
Linux support
This isn't a pull request (yet) but a question since the issue tracker is disabled for this project.
I had originally forked BrowserSelector with the main added feature being URL transformations:
URLs can be transformed by adding transformation rules to the browser key. Transformation rules are separated from the browser key using a
:
. Currently the only supported transformation is regexp replacement of the forms/find/replace/[flags]
:www.example.eu = ff:s/\.eu/.co.uk/ ; Any non-space character may be used as delimiters www.example.eu = ff:s|\.eu|.co.uk| www.example.eu = ff:s⦁\.eu⦁.co.uk⦁ ; Case-insensitive replacement (replaces "abc", "ABC", "Abc", etc.) www.example.com = ff:s/abc/def/i ; Capturing groups work too (numbered and named) example.com = ff:s|/m/(.*)|/$1| example.com = ff:s|/m/(?<subpath>.*)|/${subpath}|
I have since switched to Linux but dearly missed both the core functionality and the added URL transformations.
Given that BrowseRouter is now a .NET project – great work porting that, by the way! – it has become quite easy to port it to Linux. My branch currently contains a basic (and very hackish) proof-of-concept.
The question now: Are you interested in officially adding Linux support to BrowseRouter? If so I'd be happy to implement the missing parts (register/unregister) and clean everything up, so that it's maintainable/extendable. Otherwise I'll simply clean it up for my own personal use.
Hi mrubli!
Sorry it took two days to reply. I really need to fix my notifications. I'll also fix the issue tracker.
I am definitely for supporting Linux, which as you say is now possible since we're targeting .NET core. A while ago I had some shower thoughts about implementing it myself, but to be realistic, I don't know the Linux mechanisms to map to. So, I would be thrilled to have your contributions.
Which Linux distros would you hope to test/support? Thanks!
Sorry it took two days to reply. I really need to fix my notifications. I'll also fix the issue tracker.
You're apologizing for two days? If I did that I wouldn't get much else done. :wink:
I am definitely for supporting Linux, which as you say is now possible since we're targeting .NET core. A while ago I had some shower thoughts about implementing it myself, but to be realistic, I don't know the Linux mechanisms to map to. So, I would be thrilled to have your contributions.
Cool! I have a proof-of-concept running. Launching browsers is easy and pretty much worked out of the box after I updated config.ini
. The tricky part will be the register/unregister part. I spent a couple of minutes playing around on my system and it's a bit messy. I'll have to play around with a clean VM installation to see how exactly it's done. But basically it's a matter of creating a .desktop
file in the right place and then updating the MIME database. I found some good pointers here:
https://gitlab.com/ToS0/browserselector https://askubuntu.com/questions/16580/where-are-file-associations-stored
Which Linux distros would you hope to test/support? Thanks!
I'm personally running Debian with KDE/Plasma and assume that Ubuntu works the same way. Hopefully GNOME uses the same mechanism since they all subscribe to the XDG/freedesktop.org standards.
To be honest, users who are in the market for a tool like this probably know how to set it up if they're running a specific distro. But it'd be nice to at least get the major ones covered.
Ubuntu and Debian are my go-to distros. I think it would be good to support both KDE and Gnome. But we don't have to get in a hurry. I predict that once any Linux is supported, this project will see a lot more contributions.
On February 23, 2023 9:40:08 PM UTC, mrubli @.***> wrote:
Sorry it took two days to reply. I really need to fix my notifications. I'll also fix the issue tracker.
You're apologizing for two days? If I did that I wouldn't get much else done. :wink:
I am definitely for supporting Linux, which as you say is now possible since we're targeting .NET core. A while ago I had some shower thoughts about implementing it myself, but to be realistic, I don't know the Linux mechanisms to map to. So, I would be thrilled to have your contributions.
Cool! I have a proof-of-concept running. Launching browsers is easy and pretty much worked out of the box after I updated
config.ini
. The tricky part will be the register/unregister part. I spent a couple of minutes playing around on my system and it's a bit messy. I'll have to play around with a clean VM installation to see how exactly it's done. But basically it's a matter of creating a.desktop
file in the right place and then updating the MIME database. I found some good pointers here:https://gitlab.com/ToS0/browserselector https://askubuntu.com/questions/16580/where-are-file-associations-stored
Which Linux distros would you hope to test/support? Thanks!
I'm personally running Debian with KDE/Plasma and assume that Ubuntu works the same way. Hopefully GNOME uses the same mechanism since they all subscribe to the XDG/freedesktop.org standards.
To be honest, users who are in the market for a tool like this probably know how to set it up if they're running a specific distro. But it'd be nice to at least get the major ones covered.
-- Reply to this email directly or view it on GitHub: https://github.com/slater1/BrowseRouter/pull/3#issuecomment-1442466298 You are receiving this because you commented.
Message ID: @.***>
I reviewed your changes, and they look great. Clean and minimally invasive.
Can we find a way to keep both a Windows and a Linux ini? I would like to keep defaults that would work out of the box on a typical system.
I'm also not super committed to the ini format, but it came for free with the old version.
I reviewed your changes, and they look great. Clean and minimally invasive.
Keep in mind that this is a WIP branch at best. I wouldn't even call it a draft at this point. But I am trying to add Linux support in a way that doesn't modify the existing code too much.
Can we find a way to keep both a Windows and a Linux ini? I would like to keep defaults that would work out of the box on a typical system.
I'm also not super committed to the ini format, but it came for free with the old version.
Absolutely. Any commit whose message starts with a _
is just something I use for development and not designed to end up in the PR, so no worries there.
What I've done in a previous project that used .ini/TOML files is to add host information into the section header. This is great because you can synchronize one config file across all your machines.
In a mixed-OS environment you might have:
; Default browser settings
[browsers]
edge = microsoft-edge:{url}
ie = iexplore.exe
; Override browser settings for when host name == "myworkpc"
[browsers.myworkpc]
firefox = "C:\Program Files\Firefox\firefox.exe"
; Override browser settings for when host name == "linuxvm"
[browsers.linuxvm]
firefox = /usr/bin/firefox
Or, if you only have different Windows machines you might do this:
; Use these by default
[browsers]
firefox = "C:\Program Files\Firefox\firefox.exe"
; Overrides for an old Windows XP system
[browsers.winxp]
firefox = "C:\Program Files (x86)\ReallyOldFirefox\firefox.exe"
On Windows you would just evaluate $env:ComputerName
wheras on Linux you would run hostname
to get the host name.
There are ways to get really clever with this like letting users evaluate arbitrary environment variables or system properties inside the section headers (user names or the OS type come to mind). Maybe you have other ideas.
I have a first draft that works on Linux, including the register/unregister part. Some immediate todos remain:
- [ ] Something seems to be slightly off about the
.desktop
file. Plasma doesn't recognize it as a viable default browser and show it in the list but it can be selected manually. - [x] Some build warnings remain when building in Visual Studio. It doesn't recognize the current
#if
guards as platform-dependent and therefore complains about certain platform-specific code being reachable on all platforms. - [ ] The logger stuff needs to be cleaned up a bit, in particular file logging being on isn't a good default. Also, logging is a bit on the sparse side right now but we only have a single
Write
method. Something with more granular severity levels and the ability to show error popups on Windows might be nice.
On Linux the main usability problem right now is:
- [x] The config file is looked for in the same directory as the executable. That doesn't work if BrowseRouter is located in a system directory. It would be nice if it (also) looked in a location like
~/.config/BrowseRouter.ini
or~/.config/BrowseRouter/config.ini
.
You're doing great work.
I think your suggestion for the OS-specific section headers will work well.
Would it be possible to replace the #if
guards with a runtime check e.g. System.OperatingSystem
? I'm all for late binding, and conditional compilation can make it hard to reason about compile errors.
I can improve the logging if you don't plan to in this PR.
For locating the config file, we could add a list of search paths e.g. new[] { ".", "~/.config/BrowseRouter/" }
Sorry for the quiet period. Things suddenly got busy – as they do.
I think your suggestion for the OS-specific section headers will work well.
Ok, let me try to implement those next. While not strictly necessary for a minimum viable (Linux) product they will be helpful in my own testing and "dog-fooding".
For locating the config file, we could add a list of search paths e.g.
new[] { ".", "~/.config/BrowseRouter/" }
I had the same thought. I'll add that as well. :+1:
Would it be possible to replace the
#if
guards with a runtime check e.g.System.OperatingSystem
? I'm all for late binding, and conditional compilation can make it hard to reason about compile errors.
You can check out the version I just pushed. I got rid of all the #if
s at the cost of sprinkling System.Runtime.Versioning.SupportedOSPlatform
attributes and a few runtime checks. While it made some areas cleaner (in particular the .csproj file) the readability other areas suffered a bit (the Log
class). This can definitely be abstracted away and made nicer, so if you prefer this approach I'll go with it.
I can improve the logging if you don't plan to in this PR.
Except for those platform cleanups I don't plan to change the logging much from its current state. If you feel like reworking it now that's certainly okay but it can also be done once Linux support is in.
A more general question: Do you prefer multiple smaller PRs with minimum viable changes (e.g. one for Linux support, one for the config search paths, one for the config headers, etc.) or bigger PRs that add a new feature with everything that users might expect to land together (e.g. Linux support + multiple config search paths + config headers)?
Regarding the OS-specific section headers I've started playing around with some ideas.
To begin with I'm defining a number of variables that are automatically provided by BrowseRouter if the environment does not provide them already:
-
USER
: The current user name (Windows:$env:USERNAME
, Linux:$USER
) -
HOST
: The current host name (Windows:$env:COMPUTERNAME
, Linux:$(hostname)
) -
OS
: The operating system name ("Windows", "Linux")
We can then use these variables, along with any available environment variables to create expressions. Here are two variants, a very simple one (A) and a more powerful one (B):
Variant A:
[browsers.HOST=mywinpc]
[browsers.USER!=myusername]
[browsers.HOST=mywin*]
[browsers.OS=~/Win.*/]
Variant B:
[browsers{ "${HOST}" == "mywinpc" || ("${USER}" == "myuser" || "${OS}" =~ /Win.*/ ) }]
Variant A can be hacked up with regexps whereas Variant B is a case for a parsing library. Truth be told, I enjoy working with ASTs enormously, so I'd obviously go for the more powerful B. :-) I played around with Pidgin for a bit and it looks like a good fit for a simple case like this. But if you think that's overkill I can stick to something simpler.
Either way, the syntax is 100% up for discussion. If you have any ideas or preferences please let me know.
Hey Martin,
Thanks for these changes. Changing #if
for for attributes and runtime checks looks great.
Do you prefer multiple smaller PRs with minimum viable changes...
I appreciate your asking me this. Beggar's can't be choosers. I'm mostly interested in keeping it easy to receive contributions. So feel free to land this work all at once. In a more mature / bigger project I might have been more exacting.
Regarding section headers. Great thoughts and appreciate the options presented. I understand your interest in ASTs and wouldn't want to take that fun from you. And I see the power in Variant B. But I looked that long line and didn't feel like I could understand it at just a glance. Its power is more than I was expecting. The use case I had in mind for section headers was nothing more than "load on Linux and Windows out of the box" - understanding that each OS would have different paths e.g. /usr/bin/firefox
and C:\Program Files\Mozilla Firefox\firefox.exe
. Finally, I'm reluctant to add a dependency. Do you see a strong need for the additional environment variables? Tongue in cheek, what about [browsers.PhaseOfTheMoon=Full]
?
Bigger picture: Can I ask you what you found in BrowserRouter that made it appealing to use/contribute? Do you find broad appeal in this app? Maybe I can support more of that.
Thanks for these changes. Changing
#if
for for attributes and runtime checks looks great.
Cool, let's stick with those. I'll clean it up a bit.
Regarding section headers. Great thoughts and appreciate the options presented. I understand your interest in ASTs and wouldn't want to take that fun from you. And I see the power in Variant B. But I looked that long line and didn't feel like I could understand it at just a glance. Its power is more than I was expecting. The use case I had in mind for section headers was nothing more than "load on Linux and Windows out of the box" - understanding that each OS would have different paths e.g.
/usr/bin/firefox
andC:\Program Files\Mozilla Firefox\firefox.exe
. Finally, I'm reluctant to add a dependency. Do you see a strong need for the additional environment variables? Tongue in cheek, what about[browsers.PhaseOfTheMoon=Full]
?
I think user name and host name are really the main ones but some people might want to match against their PATH
variables instead of user/host to differentiate between systems or browser versions. We could start off simple with the [section.condition]
syntax and have the condition be a single comparison with the same operations as for the URL rules:
[browsers.HOST=myhost] ; full match
[browsers.HOST=?my*hosts?] ; wildcard match
[browsers.HOST=/my(win7|windows10)host/] ; regex match
That would provide some consistency and at least a minimum amount of expressive power. And having it evaluate environment variables on top of just USER
/HOST
/OS
is really trivial here (I have the code already). It would also leave the door open to advanced rules with a syntax like [browsers.{<fancy expressions>}]
later on.
Bigger picture: Can I ask you what you found in BrowserRouter that made it appealing to use/contribute? Do you find broad appeal in this app? Maybe I can support more of that.
As I mentioned, I was a big fan of the original BrowserSelector back in my (mainly) Windows days. The first reason was to be able to separate work and personal stuff. I tend to have Vivaldi as my default browser for personal stuff and Brave for work. It's extremely annoying when you click a Jira or GitHub link in your work Slack and it opens in your personal browser. So you end up copy/pasting all links manually into your work browser.
The second reason was that I use Invidious instead of Youtube for privacy reasons. That's why I implemented the URL transformations feature at the time. It's nice to be able to just click a Youtube link and have it open in Invidious without Google tracking your every move. It's also useful to remove those pesky UTM URL parameters, etc.
When I switched to mainly using Linux I kind of forgot about BrowserRouter. At some point I got tired of the constant copy/pasting again and I started looking if there might be an equivalent tool out there for Linux. A bunch of those tools had a GUI that would make you select a browser every time but I wanted something automatic and rule-based. Eventually I found BrowseRouter and figured it would (eventually) allow me to use a single program and rule set for all my machines, regardless of Windows/Linux.
So yeah, I'm not sure how common that scenario is but I have to think with all the home office nowadays this ought to be a rather common use case.
Thanks for the rebase
Ok, that took a bit of fiddling but I think the branch is now in an acceptable state and rebased on top of the latest master
branch. The .editorconfig
file caused a bit of a headache because it makes certain editors use CRLF line-endings even though Git handles that transparently on Linux. I'll keep an eye on that.
For the next couple of days I'll be testing this branch in my daily work and if it looks good I'll mark the PR as ready for review. Hopefully we can merge that soon and I can move on to the URL transformations.
Marking the PR as ready to review after fixing some build issues with the unit tests on Windows and rebasing onto the latest master
branch.
Thanks for opening the PR. I've been traveling but am back home now and will review it soon.
Any surprising knowledge I'd need to test this on Ubuntu?
Thanks again
I don't think there's anything surprising but, come to think of it, I should probably also write up some instructions to include in README.md
.
As I previously mentioned the auto registration doesn't entirely work yet, so I need to look into that. But it's easy enough to just browse to the binary and select it as the default browser.
Hey, I'm struggling to set my defaut browser.
I registered as root
doug@l13:~/repos/BrowseRouter/App/bin/Debug/net6.0$ sudo dotnet BrowseRouter.dll --register
[sudo] password for doug:
5/26/2023 8:59:02 AM BrowseRouter: Creating desktop file: /usr/share/applications/BrowseRouter.desktop
5/26/2023 8:59:02 AM BrowseRouter: Updating MIME cache
but it doesn't show in Default Applications. How did you do it?
Thanks!
Have you looked at the /usr/share/applications/BrowseRouter.desktop
file, in particular its Exec=
line? I've seen it not work when the executable referenced in there wasn't accessible to the current user, e.g. because I had the registered binary under /root
which my normal user couldn't access.
Another problem occurs if you run it with a dotnet BrowseRouter.dll
command like you do. If I try that my .desktop file ends up with a
Exec=/usr/share/dotnet/dotnet %u
line which obviously won't work. (It still shows up in the combo box of default applications, though. If the Settings dialog is already open I have to switch to a different category and back to "Default Applications" for it to show up.)
What I recommend is using dotnet publish
to create a single binary, then register that binary.