-
-
Notifications
You must be signed in to change notification settings - Fork 159
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[local_bookmark:1.0] feat: Implement MVP
- Loading branch information
1 parent
faeddaf
commit fd48227
Showing
2 changed files
with
151 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
# Albert Local Bookmark Plugin | ||
|
||
Open the URLs defined in the local plain text file. | ||
|
||
## The format of the bookmark file | ||
|
||
``` | ||
# Keyword 1 | ||
http://example1.com | ||
# Keyword 2, Keyword 3 | ||
http://example2.com | ||
# keyword 4 | ||
http://a.example3.com | ||
http://b.example3.com | ||
# Keyword 5 | ||
http://a.example4.com | ||
# Keyword 5 | ||
http://b.example4.com | ||
``` | ||
|
||
That is: | ||
- The keywords are preceded by a `#` and are comma-separated, and the URLs are listed below the keywords. | ||
- Empty lines are ignored. | ||
- The keyword and URL mappings can be 1 to 1, 1 to many, or many to 1. | ||
- URLs with the same keyword are allowed, as the "Keyword 5" shown in the example above. | ||
- Keywords are case-insensitive. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright (c) 2024 Chi-Sheng Liu | ||
|
||
""" | ||
Open the URLs defined in the local plain text file. | ||
See https://github.com/albertlauncher/python/local_bookmark for details | ||
""" | ||
|
||
from albert import * | ||
from pathlib import Path | ||
import webbrowser | ||
|
||
from thefuzz import fuzz | ||
|
||
md_iid = '2.0' | ||
md_version = '1.0' | ||
md_name = 'Local Bookmark' | ||
md_description = 'Open locally defined URLs in browser' | ||
md_license = "MIT" | ||
md_url = 'https://github.com/albertlauncher/python/local_bookmark' | ||
md_authors = "@MortalHappiness" | ||
md_lib_dependencies = ["thefuzz"] | ||
|
||
|
||
class LocalBookmarkPluginError(Exception): | ||
pass | ||
|
||
|
||
class Plugin(PluginInstance, TriggerQueryHandler): | ||
def __init__(self): | ||
TriggerQueryHandler.__init__(self, | ||
id=md_id, | ||
name=md_name, | ||
description=md_description, | ||
defaultTrigger='lb ') | ||
PluginInstance.__init__(self, extensions=[self]) | ||
|
||
self._file_path = self.readConfig('file_path', str) | ||
if self._file_path is None: | ||
self._file_path = "" | ||
|
||
@property | ||
def file_path(self): | ||
return self._file_path | ||
|
||
@file_path.setter | ||
def file_path(self, value): | ||
self._file_path = value | ||
self.writeConfig('file_path', value) | ||
|
||
def configWidget(self): | ||
return [ | ||
{ | ||
"type": "lineedit", | ||
"label": "Bookmark file path", | ||
"property": "file_path", | ||
}, | ||
] | ||
|
||
def handleTriggerQuery(self, query): | ||
file_path = self.file_path | ||
|
||
try: | ||
if not file_path: | ||
raise LocalBookmarkPluginError("Please set the bookmark file path in the configuration.") | ||
if not Path(file_path).is_file(): | ||
raise LocalBookmarkPluginError("The file does not exist. Please create one.") | ||
except LocalBookmarkPluginError as e: | ||
query.add( | ||
StandardItem( | ||
id=md_name, | ||
text="Error", | ||
subtext=str(e), | ||
iconUrls=["xdg:error"], | ||
) | ||
) | ||
return | ||
|
||
# Parse the file | ||
keyword_to_urls = {} | ||
current_keywords = () | ||
for line in Path(file_path).read_text().split("\n"): | ||
if not line: | ||
continue | ||
if line.startswith("#"): | ||
current_keywords = tuple(keyword.strip() for keyword in line[1:].split(",")) | ||
continue | ||
for keyword in current_keywords: | ||
keyword_to_urls.setdefault(keyword, []).append(line) | ||
|
||
search = query.string.strip().lower() | ||
if not search: | ||
query.add( | ||
StandardItem( | ||
id=md_name, | ||
text="Open the local bookmark file in editor", | ||
iconUrls=["xdg:text"], | ||
actions=[Action("config", "Open the local bookmark file in editor", | ||
lambda: runDetachedProcess(["xdg-open", file_path]))] | ||
) | ||
) | ||
return | ||
|
||
items = [] | ||
for keyword, urls in sorted(keyword_to_urls.items()): | ||
score = fuzz.token_set_ratio(search, keyword.lower()) | ||
if score: | ||
items.extend([(score, keyword, url) for url in urls]) | ||
items.sort(reverse=True, key=lambda x: x[0]) | ||
|
||
query.add([ | ||
StandardItem( | ||
id=md_name, | ||
text=keyword, | ||
subtext=url, | ||
iconUrls=["xdg:browser"], | ||
actions=[Action("open", "Open in browser", lambda u=url: webbrowser.open(u))] | ||
) for (_, keyword, url) in items | ||
]) | ||
return items |