Skip to content

Commit

Permalink
[local_bookmark:1.0] feat: Implement MVP
Browse files Browse the repository at this point in the history
  • Loading branch information
MortalHappiness committed Apr 9, 2024
1 parent faeddaf commit fd48227
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 0 deletions.
30 changes: 30 additions & 0 deletions local_bookmark/README.md
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.
121 changes: 121 additions & 0 deletions local_bookmark/__init__.py
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

0 comments on commit fd48227

Please sign in to comment.