diff --git a/README.md b/README.md index c59d24b..9c25237 100644 --- a/README.md +++ b/README.md @@ -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)
diff --git a/buku.1 b/buku.1 index 340c51b..dc6d390 100644 --- a/buku.1 +++ b/buku.1 @@ -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': diff --git a/buku.py b/buku.py index 983b93a..9ec54e8 100755 --- a/buku.py +++ b/buku.py @@ -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') diff --git a/tests/test_ExtendedArgumentParser.py b/tests/test_ExtendedArgumentParser.py index 82edb5b..337eddc 100644 --- a/tests/test_ExtendedArgumentParser.py +++ b/tests/test_ExtendedArgumentParser.py @@ -12,7 +12,7 @@ def test_program_info(platform, file): import buku prog_info_text = ''' SYMBOLS: - > title + > url + comment # tags diff --git a/tests/test_buku.py b/tests/test_buku.py index 5fd19aa..bb68802 100644 --- a/tests/test_buku.py +++ b/tests/test_buku.py @@ -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(