Show title in headline, url below

If no title, use the string "Untitled".
This commit is contained in:
Arun Prakash Jana 2017-04-09 01:49:25 +05:30
parent 07d472a0f0
commit b69007e9a6
No known key found for this signature in database
GPG Key ID: A75979F35C080412
5 changed files with 29 additions and 56 deletions

View File

@ -42,7 +42,7 @@
### Introduction
`buku` is a powerful bookmark management utility written in Python3 and SQLite3. When I started writing it, I couldn't find a flexible cmdline solution with a private, portable, merge-able database along with browser integration. Hence, `buku` (after my son's nickname).
`buku` is a powerful bookmark manager written in Python3 and SQLite3. When I started writing it, I couldn't find a flexible cmdline solution with a private, portable, merge-able database along with browser integration. Hence, `buku` (after my son's nickname).
`buku` fetches the title of a bookmarked web page and stores it along with any additional comments and tags. You can use your favourite editor to compose and update bookmarks. With multiple search options, including regex and a deep scan mode (particularly for URLs), it can find any bookmark instantly. Multiple search results can be opened in the browser at once.
@ -227,7 +227,7 @@ POWER TOYS:
-z, --debug show debug information and verbose logs
SYMBOLS:
> title
> url
+ comment
# tags
```
@ -241,7 +241,7 @@ SYMBOLS:
- **$PWD** on both Windows and non-Windows systems.
- If the URL contains characters like `;`, `&` or brackets they may be interpreted specially by the shell. To avoid it, add the URL within single or double quotes (`'`/`"`).
- URLs are unique in DB. The same URL cannot be added twice.
- Bookmarks with immutable titles are listed with `(L)` after the URL.
- Bookmarks with immutable titles are listed with `(L)` after the title.
- **Tags**:
- Comma (`,`) is the tag delimiter in DB. A tag cannot have comma(s) in it. Tags are filtered (for unique tags) and sorted. Tags are stored in lower case and can be replaced, appended or deleted.
- Folder names are converted to all-lowercase tags during bookmarks html import.
@ -264,7 +264,7 @@ SYMBOLS:
- --deep : match **substrings** (`match` matches `rematched`) in URL, title and tags.
- --sreg : match a regular expression (ignores --deep).
- --stag : search bookmarks by a tag, or list all tags alphabetically with usage count (if no arguments).
- Search results are indexed serially. This index is different from actual database index of a bookmark record which is shown within `[]` after the URL.
- Search results are indexed serially. This index is different from actual database index of a bookmark record which is shown within `[]` after the title.
- **Encryption** is optional and manual. AES256 algorithm is used. To use encryption, the database file should be unlocked (-k) before using `buku` and locked (-l) afterwards. Between these 2 operations, the database file lies unencrypted on the disk, and NOT in memory. Also, note that the database file is *unencrypted on creation*.
- **Editor** support:
- A single bookmark can be edited before adding. The editor can be set using the environment variable *EDITOR* or by explicitly specifying the editor. The latter takes preference. If -a is used along with -w, the details are populated in the editor template.
@ -371,16 +371,16 @@ NOTE: This flexibility is not exposed in the program.
2. **Add** a bookmark with **tags** `search engine` and `privacy`, **comment** `Search engine with perks`, **fetch page title** from the web:
$ buku -a https://ddg.gg search engine, privacy -c Search engine with perks
336. https://ddg.gg
> DuckDuckGo
336. DuckDuckGo
> https://ddg.gg
+ Alternative search engine with perks
# privacy,search engine
where, >: title, +: comment, #: tags
where, >: url, +: comment, #: tags
3. **Add** a bookmark with tags `search engine` & `privacy` and **immutable custom title** `DDG`:
$ buku -a https://ddg.gg search engine, privacy --title 'DDG' --immutable 1
336. https://ddg.gg (L)
> DDG
336. DDG (L)
> https://ddg.gg
# privacy,search engine
Note that URL must precede tags.
4. **Add** a bookmark **without a title** (works for update too):
@ -512,7 +512,6 @@ NOTE: This flexibility is not exposed in the program.
- [Arun Prakash Jana](https://github.com/jarun)
- [Rachmadani Haryono](https://github.com/rachmadaniHaryono)
- [Kishore Narendran](https://github.com/kishore-narendran)
Copyright © 2015-2017 [Arun Prakash Jana](mailto:engineerarun@gmail.com)
<br>

8
buku.1
View File

@ -38,7 +38,7 @@ If the URL contains characters like ';', '&' or brackets they may be interpreted
URLs are unique in DB. The same URL cannot be added twice.
.PP
.IP 4. 4
Bookmarks with immutable titles are listed with '(L)' after the URL.
Bookmarks with immutable titles are listed with '(L)' after the title.
.PP
.IP 5. 4
\fBTags\fR:
@ -69,7 +69,7 @@ Bookmarks with immutable titles are listed with '(L)' after the URL.
- --deep : match \fBsubstrings\fR (`match` matches `rematched`) in URL, title and tags.
- --sreg : match a regular expression (ignores --deep).
- --stag : search bookmarks by a tag, or list all tags alphabetically with usage count (if no arguments).
- Search results are indexed serially. This index is different from actual database index of a bookmark record which is shown within '[]' after the URL.
- Search results are indexed serially. This index is different from actual database index of a bookmark record which is shown within '[]' after the title.
.PP
.IP 9. 4
\fBEncryption\fR is optional and manual. AES256 algorithm is used. To use encryption, the database file should be unlocked (-k) before using \fBbuku\fR and locked (-l) afterwards. Between these 2 operations, the database file lies unencrypted on the disk, and NOT in memory. Also, note that the database file is \fBunencrypted on creation\fR.
@ -126,7 +126,7 @@ Set the title of a bookmark immutable during updates. Works with --add, --update
.SH SEARCH OPTIONS
.TP
.BI \-s " " \--sany " keyword [...]"
Search bookmarks with ANY of the keyword(s) in URL, title or tags and show the results. Prompts to enter result number to open in browser. Note that the sequential result index is not the DB index. The DB index is shown within '[]' after the URL.
Search bookmarks with ANY of the keyword(s) in URL, title or tags and show the results. Prompts to enter result number to open in browser. Note that the sequential result index is not the DB index. The DB index is shown within '[]' after the title.
.br
This is the default search option for positional arguments if no other search option is specified.
.TP
@ -330,7 +330,7 @@ The first command picks editor from the environment variable \fIEDITOR\fR. The s
.EE
.PP
.IP "" 4
In the output, >: title, +: comment, #: tags.
In the output, >: url, +: comment, #: tags.
.PP
.IP 3. 4
\fBAdd\fR a bookmark with tags 'search engine' & 'privacy' and \fBimmutable custom title\fR 'DDG':

31
buku.py
View File

@ -48,10 +48,10 @@ SKIP_MIMES = {'.pdf', '.txt'}
colorize = True # Allow color output by default
# Default colour to print records
ID_str = '\x1b[96;1m%d. \x1b[0;2m%s\x1b[0;2m [%s]\x1b[0m\n'
ID_DB_str = '\x1b[96;1m%d. \x1b[0;2m%s\x1b[0m'
ID_str = '\x1b[96;1m%d. \x1b[1;92m%s\x1b[0;2m [%s]\x1b[0m\n'
ID_DB_str = '\x1b[96;1m%d. \x1b[1;92m%s\x1b[0m'
MUTE_str = '%s \x1b[2m(L)\x1b[0m\n'
TITLE_str = '%s \x1b[91m>\x1b[0m \x1b[1;92m%s\x1b[0m\n'
URL_str = '%s \x1b[91m>\x1b[0m \x1b[2m%s\x1b[0m\n'
DESC_str = '%s \x1b[91m+\x1b[0m %s\n'
TAG_str = '%s \x1b[91m#\x1b[0m %s\n'
@ -817,12 +817,12 @@ class BukuDb:
if self.colorize:
bad_url_str = '\x1b[1mIndex %d: Malformed URL\x1b[0m\n'
mime_str = '\x1b[1mIndex %d: HTTP HEAD requested\x1b[0m\n'
blank_title_str = '\x1b[1mIndex %d: No title\x1b[0m\n'
blank_URL_str = '\x1b[1mIndex %d: No title\x1b[0m\n'
success_str = 'Title: [%s]\n\x1b[92mIndex %d: updated\x1b[0m\n'
else:
bad_url_str = 'Index %d: Malformed URL\n'
mime_str = 'Index %d: HTTP HEAD requested\n'
blank_title_str = 'Index %d: No title\n'
blank_URL_str = 'Index %d: No title\n'
success_str = 'Title: [%s]\nIndex %d: updated\n'
query = 'UPDATE bookmarks SET metadata = ? WHERE id = ?'
@ -871,7 +871,7 @@ class BukuDb:
cond.release()
continue
elif title == '':
print(blank_title_str % row[0])
print(blank_URL_str % row[0])
cond.release()
continue
@ -1771,7 +1771,7 @@ class ExtendedArgumentParser(argparse.ArgumentParser):
file.write('''
SYMBOLS:
> title
> url
+ comment
# tags
@ -2297,23 +2297,22 @@ def print_single_rec(row, idx=0):
:param idx: search result index. If 0, print with DB index
'''
# Start with index and URL
# Start with index and title
if idx != 0:
pr = ID_str % (idx, row[1], row[0])
pr = ID_str % (idx, row[2] if row[2] else 'Untitled', row[0])
else:
pr = ID_DB_str % (row[0], row[1])
pr = ID_DB_str % (row[0], row[2] if row[2] else 'Untitled')
# Indicate if record is immutable
if row[5] & 1:
pr = MUTE_str % (pr)
else:
pr += '\n'
# Append title
if row[2] != '':
pr = TITLE_str % (pr, row[2])
# Append URL
pr = URL_str % (pr, row[1])
# Append description
if row[4] != '':
if row[4]:
pr = DESC_str % (pr, row[4])
# Append tags IF not default (delimiter)
@ -2699,7 +2698,7 @@ def piped_input(argv, pipeargs=None):
# main starts here
def main():
global colorize, ID_str, ID_DB_str, MUTE_str, TITLE_str, DESC_str, TAG_str
global colorize, ID_str, ID_DB_str, MUTE_str, URL_str, DESC_str, TAG_str
title_in = None
tags_in = None
@ -2902,7 +2901,7 @@ POSITIONAL ARGUMENTS:
ID_str = '%d. %s [%s]\n'
ID_DB_str = '%d. %s'
MUTE_str = '%s (L)\n'
TITLE_str = '%s > %s\n'
URL_str = '%s > %s\n'
DESC_str = '%s + %s\n'
TAG_str = '%s # %s\n'
logging.basicConfig(format='[%(levelname)s] %(message)s')

View File

@ -12,7 +12,7 @@ def test_program_info(platform, file):
import buku
prog_info_text = '''
SYMBOLS:
> title
> url
+ comment
# tags

View File

@ -151,31 +151,6 @@ def test_edit_at_prompt(nav, is_editor_valid_retval, edit_rec_retval):
row5=st.integers(),
)
def test_print_single_rec(idx, row0, row1, row2, row3, row4, row5):
"""test func."""
row = [row0, row1, row2, row3, row4, row5]
pr = None
with mock.patch('buku.print') as m_print:
import buku
buku.print_single_rec(row, idx)
if idx != 0:
pr = buku.ID_str % (idx, row1, row0)
else:
pr = buku.ID_DB_str % (row0, row1)
if row5 & 1:
pr = buku.MUTE_str % (pr)
else:
pr += '\n'
if row2 != '':
pr = buku.TITLE_str % (pr, row2)
if row4 != '':
pr = buku.DESC_str % (pr, row4)
if row3 != buku.DELIM:
pr = buku.TAG_str % (pr, row3[1:-1])
m_print.assert_called_once_with(pr)
@pytest.mark.parametrize(