├── History.md ├── Makefile ├── Readme.md ├── black-Linen.png ├── bm ├── licenses.txt └── scripts ├── bmflyounet_to_bm060.sh └── bmtj_to_bm060.sh /History.md: -------------------------------------------------------------------------------- 1 | 2 | 0.6.5 / 2016-03-xx 3 | ================== 4 | 5 | * In some case, the sed operation to grab the title is not working. For those who have `hxselect` installed, it should always work. 6 | * With `-E` the bm.lnk file is open with your $EDITOR (default is vi). 7 | * With `-q` bm looks for the Title of the web page. 8 | * Fix : When grabing the picture with `-P` bm used the md5 instead of the URL. 9 | 10 | 0.6.4 / 2016-03-22 11 | ================== 12 | 13 | * Fix : When searching for a tag and Title contains |. Results were incorrect. 14 | 15 | 0.6.3 / 2016-03-11 16 | ================== 17 | 18 | * Fix #20 : Issue with tags when a Title contains a comma. Stats are weird. 19 | 20 | 0.6.2 / 2016-03-08 21 | ================== 22 | 23 | * Changing the curl call. Now follow links (eg. the 301 code). 24 | * Fix #18 : Issue with BM on Apple (related to readlink binary). 25 | 26 | 0.6.1 / 2016-02-23 27 | ================== 28 | 29 | * Adding permissive licenses : 30 | * - WTFPL : do What The Fuck you Want to Public License 31 | * - DSSL : Demerden Sie Sich License 32 | 33 | 0.6.0 / 2016-02-21 34 | ================== 35 | 36 | * Fields order is now modified. Date is now the second field instead of last. 37 | * 2 scripts are present to migrate from tj/bm and fromo Flyounet/bm to the v0.6.0. 38 | * Fix #17 : Add a Flag (-r) to open image stored for a link. 39 | * Fix #18 : Store a date for the screenshot taken. 40 | * Fix #19 : Add a Flag (-P) to take the screenshot for a specific link. 41 | * Updated the function related to statistic to also include config info and orphaned pictures. 42 | * Added 2 Flags -n (-N) to sort results by date (reverse) 43 | 44 | 0.5.3 / 2016-02-16 45 | ================== 46 | 47 | * Documentation update 48 | * History update 49 | 50 | 0.5.2 / 2016-02-11 51 | ================== 52 | 53 | * Fix #15 : Title with Pipe not working (and also correct the delete function due to this correction) 54 | * Fix #16 : Autoincrement doesn't work for more than 9 item 55 | 56 | 0.5.1 / 2016-02-02 57 | ================== 58 | 59 | * Added an alternate print list with `-z` 60 | * HTML file generated should be good in validators 61 | 62 | 0.5.0 / 2016-02-01 63 | ================== 64 | 65 | * Engine rewritted 66 | * Added tons of configuration variables 67 | * Added use of `cutycapt` for Linux 68 | * Added duplicate check 69 | * Added Accelerator to find your bookmark 70 | * Changed interface, the old one still exist but new functions use arguments `-a`, `-t`, ... 71 | * Generate screenshot when added in bookmark 72 | * Added backup 73 | * And more, see source or help. 74 | 75 | 0.4.0 / 2012-03-30 76 | ================== 77 | 78 | * Added new HTML style 79 | 80 | 0.3.0 / 2012-03-15 81 | ================== 82 | 83 | * Added: use webkit2png for thumbs. Closes #2 84 | 85 | 0.2.0 / 2012-03-15 86 | ================== 87 | 88 | * Added nicer display for large urls 89 | * Added: strip http:// when listing 90 | 91 | 0.1.0 / 2012-03-15 92 | ================== 93 | 94 | * Added experimental screenshots feature 95 | 96 | 0.0.1 / 2012-03-15 97 | ================== 98 | 99 | - Initial release 100 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | PREFIX=/usr/local 3 | 4 | install: 5 | cp -f bm $(PREFIX)/bin/bm 6 | if [ ! -d "/usr/share/bm" ]; then mkdir -p "/usr/share/bm"; fi 7 | cp -f "black-Linen.png" "/usr/share/bm/black-Linen.png" 8 | cp -f Makefile "/usr/share/bm/Makefile" 9 | 10 | uninstall: 11 | rm -f $(PREFIX)/bin/bm 12 | rm -f "/usr/share/bm/black-Linen.png" 13 | rm -f "/usr/share/bm/Makefile" 14 | rmdir "/usr/share/bm" 15 | 16 | .PHONY: install uninstall 17 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | 2 | ## BM 3 | 4 | Simple bash CLI bookmarks. 5 | 6 | Firstly designed for Mac and now also for Linux, supports search on criteria, 7 | accelerator, tags, Screenshots, configuration file, backup, and also 8 | generate a HTML file with bookmarks and Screenshots. 9 | 10 | **/!\ : version prior to v0.6.6 had a bug when deleting. Don't use the delete function or update !** 11 | If you upgrade from a version prior to v0.6.0, read at the end. 12 | 13 | ![](http://cl.ly/FREx/Screen%20Shot%202012-03-29%20at%2011.15.14%20PM.png) 14 | 15 | Please note, BM needs some binaries to work see configuration to change them): 16 | 17 | * For the Screenshot part: 18 | * - `cutycapt` for Linux 19 | * - `webkit2png` for Mac. 20 | * For the clipboard copy: 21 | * - `xsel` for Linux 22 | * - As I don't have any Mac, nothing for the time being. 23 | * For the md5 part: 24 | * - `md5sum` for Linux 25 | * - `md5` for Mac. 26 | * Other tools: `sed`, `awk`, `date`, `iconv`, `cat`, `curl`, `column` and `bash` 27 | 28 | ## Install 29 | 30 | ``` 31 | $ make install 32 | $ make uninstall 33 | ``` 34 | 35 | ## Example 36 | 37 | Add a bookmark: 38 | 39 | $ bm add http://subtlepatterns.com "tiling background images" design textures 40 | 41 | Open it later: 42 | 43 | $ bm subtle 44 | 45 | Search for design related bookmarks: 46 | 47 | ![cli bookmarks](http://f.cl.ly/items/0s3M0T1B122L3W1C1L1U/Screen%20Shot%202012-03-15%20at%204.44.24%20PM.png) 48 | 49 | ## Usage 50 | 51 | ``` 52 | Usage: ./bm [modifier(s)] command [option(s)] 53 | 54 | Commands : 55 | ========== 56 | -h Print this help 57 | -H Print help for legacy usage 58 | -v/-V Print the version 59 | -a 'URL' Add the URL to bookmark file 60 | Options for -a 61 | -t "TagList" Tags are sparated by a comma , 62 | -T "Title" Title for this URL (if empty and allowed Title 63 | downloaded) 64 | -A "accel" Accelerator when search for URLs (start with Accel) 65 | Default is FQDN without gTld (and www, and sheme) 66 | -F Force the bookmark to be created (even if duplicate 67 | or invalid) 68 | -p Force the screenshot to be taken 69 | 70 | -l List all URLs (default action, same thing as calling bm without args) 71 | Options for -l 72 | -z Use the alternate print list 73 | -n Sort the results by date 74 | -N Sort the results by date (reverse) 75 | 76 | 77 | -s 'object' Search for bookmarks 78 | Options for -s 79 | -i Incensitive case search 80 | -z Use the alternate print list 81 | -n Sort the results by date 82 | -N Sort the results by date (reverse) 83 | Objects are 84 | :string Search in accelerator list 85 | +string Search in tags list 86 | =string Search in MD5 list 87 | /string Search in URL list 88 | string Search in full test 89 | 90 | -o 'object' Search for bookmarks and open it (use the same argument as for -s) 91 | Options for -o 92 | -i Incensitive case search 93 | -O If more than one answer force the first bookmark to be open 94 | -Y If more than one answer force ALL bookmarks to be open 95 | 96 | -x 'object' Search for bookmarks and copy it to clipboard (use the same argument as for -s) 97 | Options for -x 98 | -i Incensitive case search 99 | -X If more than one answer force the first bookmark to be copied 100 | -Y If more than one answer force ALL bookmarks to be copied 101 | 102 | -r 'object' Search for bookmarks and Print the recorded associated picture (use the same argument as for -s) 103 | Options for -r 104 | -i Incensitive case search 105 | -O If more than one answer force the first bookmark to have its picture printed 106 | -Y If more than one answer force ALL bookmarks to have their picture printed 107 | 108 | -d 'URL' or Delete the URL from bookmark file 109 | md5sum or 110 | 'URL part' Options for -d 111 | -D Delete first occurence only 112 | -F Force the bookmark to be deleted (even if duplicate) 113 | -p Delete the associated picture (no trash available) 114 | 115 | -g Generate a HTML page with all bookmarks 116 | If used more than once, generate a page per tag 117 | Options for -g 118 | -G "filename" If g==1 then generate then use this filename to generate page 119 | -O Open the file when generated 120 | 121 | -P 'object' Generate all Non existant picture (check done for all URL in bm), if none argument. 122 | If an argument is given (use the same argument as for -s) only the results will have a picture. 123 | Options for -P 124 | -F Force the picture to be taken again (even if already exists). 125 | 126 | -L List all tags 127 | 128 | -C Print the color table (usefull for configuration) 129 | 130 | -S Show statistics about bookmarks/tags (and also configuration) 131 | Options for -S 132 | -p Print the list of orphaned Pictures 133 | 134 | Modifiers : 135 | =========== 136 | -c 'file' Use this configuration file instead of the default one 137 | 138 | -b 'file' Use this bookmark file instead of the default one 139 | 140 | Old Legacy usage still available : 141 | Usage: bm [options] [cmd] 142 | 143 | Commands: 144 | 145 | # add a bookmark with the given url, description, and optional tags 146 | $ bm add [desc] [tag...] [accelerator] 147 | 148 | # open the first bookmark matching 149 | $ bm open 150 | $ bm 151 | 152 | # search the bookmarks via full-text 153 | $ bm search 154 | 155 | # list tags 156 | $ bm tags 157 | 158 | # list bookmarks available 159 | $ bm list 160 | $ bm ls 161 | $ bm 162 | 163 | # display statistics about the bookmarks 164 | $ bm statistics 165 | $ bm stats 166 | 167 | # view bookmark screenshots in your default browser 168 | $ bm view design 169 | $ bm view 170 | 171 | # clear all bookmarks 172 | $ bm clear 173 | 174 | Options: 175 | 176 | -V output bm version 177 | -h output help information for new parameters 178 | -H output this help information 179 | ``` 180 | 181 | 182 | ## Screenshots 183 | 184 | Run `bm view [query]` to view the bookmark screenshots in your default browser. This requires `webkit2png(1)` (`brew install webkit2png`). 185 | 186 | ## Storage 187 | 188 | Store the file(s) wherever you want. Use configuration (either internal or with a config file with `-c`), or parameters (`-b` for bookmark file). 189 | 190 | ``` 191 | $ cat ~/sync/bm.lnk 192 | bd8b3eff7fa82a0382a3e7576c5363b6|:bm|https://github.com/Flyounet/bm/|bm a cool enhanced bookmark tool for your console|default,shell|2016-01-18T07:21:36Z 193 | 2981b5cae113491ddb18e0d51454f0d9|:bmtj|https://github.com/tj/bm/|The original bm : a cool bookmark tool for your console|default,shell|2016-01-18T07:21:36Z 194 | #fd65acec3e2abff9d2fd3c581df3142d|:7|http://flyounet.net|http-flyounet-net|site,dev, bli,bla,blo,bli|2016-01-20T17:44:02Z 195 | # fd65acec3e2abff9d2fd3c581df3142d|:9|http://flyounet.net|http-flyounet-net|site,dev, ba,bello,belli,bella,arthur,toto,titi,tata,bli,bla,blo,bli|2016-01-20T17:46:24Z 196 | ac313b7d866bc76487858b243f9f3ff0|:HP|http://localhost:631/printers/HP8600|Cups: Imprimante HP 8600|admin,cups,local|2016-01-31T18:33:11Z 197 | ae6461ffeb6cd8393c4c100d026db789|:sync|https://127.0.0.1:8384/|SyncThings Local|admin,network,syncthings|2016-01-31T19:05:08Z 198 | 7ad10b8decf3ef55ce4e8a95e80f4b9d|:home|http://flyounet.net/life|3615 my life|blog,home|2016-01-31T21:09:33Z 199 | 7a3a43da3e8b8f58e5ade40eab35a1fd|:syntaxe|http://flyounet.net/life/2015-11-01-time-to-markdown.html|Syntaxe markdown|blog,home,markdown|2016-01-31T21:12:11Z 200 | ``` 201 | Please note the above format is not used anymore since the v0.6.0. The date has been put as the second field of bookmark file. 202 | 203 | If you don't want to see some bookmarks, but want to keep them, you could comment them by adding a hash `#`. 204 | 205 | ## Statistics 206 | 207 | bm provides you some statistics usage 208 | 209 | ``` 210 | $ bm -S -p 211 | 212 | ===== Configuration ===== 213 | Bookmark file : /home/testuser/bm.lnk 214 | Config file : /home/testuser/bm.conf (but doesn't exist) 215 | Trash file : /home/testuser/.bm.trash 216 | Screenshot directory : /home/testuser/.bm.shots 217 | Backup file(s) : /home/testuser/.bm.lnk.bck* 218 | /home/testuser/.bm.lnk.bck.0 219 | /home/testuser/.bm.lnk.bck.1 220 | /home/testuser/.bm.lnk.bck.2 221 | 222 | ===== Statistics ===== 223 | # of Bookmarks : 27 224 | # of Duplicate : 0 225 | # of tags : 26 226 | Top 14 tags used : 227 | admin:8 color:7 bash:7 prompt:6 git:4 design:4 css:4 228 | box:4 system:3 network:3 ecryptfs:3 doc:3 rpi:2 lprab:2 229 | # of Pictures : 34 [# of files in /home/testuser/.bm.shots:39] 230 | All Pictures size : 27M 231 | Bookmark Without Pic : 0 232 | Orphaned pictures : 7 233 | 234 | ===== Orphaned ===== 235 | List of orphaned pictures : 236 | - /home/testuser/.bm.shots/16d402a7f1be2304f90ec25924782edc.png [Trashed URL should be: https://github.com/Flyounet/bm] 237 | - /home/testuser/.bm.shots/2981b5cae113491ddb18e0d51454f0d9.png [Trashed URL should be: ] 238 | - /home/testuser/.bm.shots/7a3a43da3e8b8f58e5ade40eab35a1fd.png [Trashed URL should be: Unknown] 239 | - /home/testuser/.bm.shots/7ad10b8decf3ef55ce4e8a95e80f4b9d.png [Trashed URL should be: Unknown] 240 | - /home/testuser/.bm.shots/b88fe41f6aa05370e81bae926da2087c.png [Trashed URL should be: Unknown] 241 | - /home/testuser/.bm.shots/bd8b3eff7fa82a0382a3e7576c5363b6.png [Trashed URL should be: ] 242 | - /home/testuser/.bm.shots/c5c24b5609b0191095197d19d852eb1c.png [Trashed URL should be: http://toto] 243 | 244 | ``` 245 | 246 | ## v0.6.0 and above... 247 | 248 | The field's order has been changed. To use the v0.6.0, you have to execute the migration tool located in the `scripts` subdirectory. 249 | It will modify your bookmark file for you (and do a backup first). 250 | 251 | ## Licenses 252 | 253 | * WTFPL : do What The Fuck you Want to Public License 254 | * DSSL : Demerden Sie Sich License 255 | 256 | -------------------------------------------------------------------------------- /black-Linen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tj/bm/35412a6bc4f7c533ce8d22da1d199380d6fd9b11/black-Linen.png -------------------------------------------------------------------------------- /bm: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # /*------------------------------------------------------------------------*\ 4 | # | | 5 | # | WTFPL & DSSL apply on this material. | 6 | # | | 7 | # +--------------------------------------------------------------------------+ 8 | # | | 9 | # | bm : A Bash CLI bookmark manager | 10 | # | Copyright (C) 2012 TJ Holowaychuk — Tous droits réservés. | 11 | # | Copyright (C) 2016 Flyounet — Tous droits réservés. | 12 | # | | 13 | # | Cette œuvre est distribuée SANS AUCUNE GARANTIE hormis celle d'être | 14 | # | distribuée sous les termes de la Licence Demerdez-vous («Demerden Sie | 15 | # | Sich License») telle que publiée par Flyounet : soit la version 1 de | 16 | # | cette licence,soit (à votre gré) toute version ultérieure. | 17 | # | telle que publiée par Flyounet : soit la version 1 de cette licence, | 18 | # | soit (à votre gré) toute version ultérieure. | 19 | # | | 20 | # | Vous devriez avoir reçu une copie de la Licence Démerdez-vous avec cette | 21 | # | œuvre ; si ce n’est pas le cas, consultez : | 22 | # | . | 23 | # | | 24 | # \*------------------------------------------------------------------------*/ 25 | 26 | 27 | # default filename for Baker config file (just the filename no path) 28 | readonly _BM_DEFAULT_CONFIG_FILENAME="${_BM_DEFAULT_CONFIG_FILENAME:=bm.conf}" 29 | 30 | 31 | config() { 32 | #echo "Reading Configuration..." >&2 33 | [[ "${__w:=$HOME}" != "${HOME}" ]] && echo "Working dir changed to ${__w}" 34 | [[ "${__w: -1}" != '/' ]] && __w="${__w//\/\//\/}/" 35 | if [ ${__B:=0} -eq 0 ]; then 36 | # If a config file is given, we take it first, or look for a default config file 37 | export _BM_CONFIG_FILE="${__w}${_BM_DEFAULT_CONFIG_FILENAME}" 38 | if [ "$(uname -s)" = 'Linux' -a -f "$(readlink -m "${1:-}" 2>/dev/null)" ]; then 39 | export _BM_CONFIG_FILE="${1}" 40 | . "${1}" 41 | elif [ -e "${1}" ]; then 42 | export _BM_CONFIG_FILE="${1}" 43 | . "${1}" 44 | elif [ ${__n:=0} -eq 0 -a -f "${__w}${_BM_DEFAULT_CONFIG_FILENAME}" ]; then 45 | . "${__w}${_BM_DEFAULT_CONFIG_FILENAME}" 46 | #echo "Default config file loaded ${__w}${_BM_DEFAULT_CONFIG_FILENAME}" 47 | fi 48 | else 49 | export _BM_CONFIG_FILE='none' 50 | fi 51 | # _BM_BOOKMARK_FILE : Where is stored the bookmark file 52 | export _BM_BOOKMARK_FILE="${_BM_BOOKMARK_FILE:=${__w}bm.lnk}" 53 | 54 | # _BM_BOOKMARK_BACKUP_FILE : Where is stored the backup of bookmark file 55 | export _BM_BOOKMARK_BACKUP_FILE="${_BM_BOOKMARK_BACKUP_FILE:=${__w}.bm.lnk.bck}" 56 | 57 | # _BM_HTML_FILE : Location of generated HTML file 58 | export _BM_HTML_FILE="${_BM_HTML_FILE:=${__w}bm.html}" 59 | 60 | # _BM_DELETE_FILE : Where to find the deleted URLs 61 | export _BM_DELETE_FILE="${_BM_DELETE_FILE:=${__w}.bm.trash}" 62 | 63 | # _BM_BOOKMARK_BACKUP : Copy the bookmark file before each modification 64 | export _BM_BOOKMARK_BACKUP=${_BM_BOOKMARK_BACKUP:=true} 65 | 66 | # _BM_BOOKMARK_BACKUP_VERSION : How many copy to keep (0 for 1, 1 for 2, ...) 67 | export _BM_BOOKMARK_BACKUP_VERSION=${_BM_BOOKMARK_BACKUP_VERSION:=2} 68 | 69 | # _BM_DELETE_ALLOWED : Even with the force flag the delete function will not be allowed (true or false) 70 | export _BM_DELETE_ALLOWED=${_BM_DELETE_ALLOWED:=true} 71 | 72 | # _BM_DELETE_TO_FILE : Allow or disallow the deleted URLs to be copied in the Trash (true or false) 73 | export _BM_DELETE_TO_FILE=${_BM_DELETE_TO_FILE:=true} 74 | 75 | # _BM_DELETE_PICTURE : Allow or disallow the picture associated to a URL to be deleted (true or false) 76 | export _BM_DELETE_PICTURE=${_BM_DELETE_PICTURE:=true} 77 | 78 | # _BM_DUPS_DETECT : Look for duplicates URL before insert in bookmark file (ovverided by -F) 79 | export _BM_DUPS_DETECT=${_BM_DUPS_DETECT:=true} 80 | 81 | # _BM_ASK_BEFORE_OPEN : When using bm with a URL (or search term) ask before opening the browser if more than one answer 82 | export _BM_ASK_BEFORE_OPEN=${_BM_ASK_BEFORE_OPEN:=true} 83 | 84 | # _BM_GET_PAGE_TITLE : When adding a URL execute a curl command to get the if none given 85 | export _BM_GET_PAGE_TITLE=${_BM_GET_PAGE_TITLE:=true} 86 | 87 | # _BM_SCREENSHOT_DIRECTORY : Where to store the screenshot taken 88 | export _BM_SCREENSHOT_DIRECTORY="${_BM_SCREENSHOT_DIRECTORY:=${__w}.bm.shots}" 89 | 90 | # _BM_SCREENSHOT_GET : When adding a URL try to take a screenshot in background 91 | export _BM_SCREENSHOT_GET=${_BM_SCREENSHOT_GET:=true} 92 | 93 | # _BM_SCREENSHOT_WAIT : When taking a screenshot wait for the action to finish 94 | export _BM_SCREENSHOT_WAIT=${_BM_SCREENSHOT_WAIT:=false} 95 | 96 | # _BM_OPEN_FIRST : When using open, the first link found is open 97 | # Also work with the copy to clipboard function 98 | export _BM_OPEN_FIRST=${_BM_OPEN_FIRST:=false} 99 | 100 | # _BM_OPEN_ALL : When using open, if more than one result, all are open (with the same function) 101 | # Also work with the copy to clipboard function (overrided by -Y) 102 | export _BM_OPEN_ALL=${_BM_OPEN_ALL:=false} 103 | 104 | # _BM_NO_ARGS_FORCE_HELP : If no args given to script sends to help instead of list all link 105 | export _BM_NO_ARGS_FORCE_HELP=${_BM_NO_ARGS_FORCE_HELP:=false} 106 | 107 | # _BM_CREATE_BOOKMARK_FILE : If bm is called to list and no file exists. bm will create a default one. 108 | export _BM_CREATE_BOOKMARK_FILE=${_BM_CREATE_BOOKMARK_FILE:=true} 109 | 110 | # _BM_CMD_CAPTURE_CHECK : If you don't have tool installed to take screenshot, just put to false. 111 | # It will disable the _BM_GET_SCREENSHOT. 112 | export _BM_CMD_CAPTURE_CHECK=${_BM_CMD_CAPTURE_CHECK:=true} 113 | 114 | # I suppose the uname command is available 115 | # Please note, the PRE & POST capture command will not be analyzes nor verified. 116 | if [ "$(uname -s)" = 'Linux' ]; then 117 | export _BM_CMD_IMAGE_OPEN='feh' 118 | export _BM_CMD_OPEN='xdg-open' 119 | export _BM_CMD_PRE_CAPTURE='' 120 | export _BM_CMD_CAPTURE='cutycapt' 121 | export _BM_CMD_CAPTURE_ARGS='--insecure --url={URL} --out={FILE}' 122 | export _BM_CMD_POST_CAPTURE='' 123 | export _BM_CMD_MD5='md5sum' 124 | export _BM_CMD_COPY='xsel' 125 | else 126 | # To keep commpatibility with the Mac (even i don't have any) 127 | export _BM_CMD_IMAGE_OPEN='open' 128 | export _BM_CMD_OPEN='open' 129 | export _BM_CMD_PRE_CAPTURE='' 130 | export _BM_CMD_CAPTURE='webkit2png' 131 | export _BM_CMD_CAPTURE_ARGS='-C -o {FILE}.png {URL}' 132 | export _BM_CMD_POST_CAPTURE='cp -- "{FILE}-clipped.png" "{FILE}" ; rm -f -- {FILE}-{clipped,full,thumb}.png' 133 | export _BM_CMD_MD5='md5' 134 | export _BM_CMD_COPY='xsel' 135 | fi 136 | 137 | # _BM_PRINT_LINE : This line is used to print datas 138 | # export _BM_PRINT_LINE="${_BM_PRINT_LINE:=${UNDERLINE}${GRAY_LIGHT}BM_URL${RESET} --> ${RESET}BM_TITLE ${GRAY_DARK}[BM_TAGS]\n${BOLD}${GRAY}BM_ACCEL ${GRAY_DARK}(BM_MD5)${RESET} - ${GRAY_DARK}Added: BM_DATE${RESET}}" 139 | export _BM_PRINT_LINE="${_BM_PRINT_LINE:=${BOLD}${GRAY}BM_ACCEL ${RESET}${DIM}-->${RESET} ${GRAY_LIGHT}BM_TITLE ${GRAY_DARK}${BOLD}[BM_TAGS]${RESET}\n${UNDERLINE}${DIM}BM_URL${RESET} - ${GRAY_DARK}Added: BM_DATE${RESET}}" 140 | 141 | # _BM_PRINT_LINE_ALTERNATIVE : This line is used to print datas 142 | export _BM_PRINT_LINE_ALTERNATIVE="${_BM_PRINT_LINE_ALTERNATIVE:=${BOLD}${GRAY}BM_ACCEL ${RESET}${DIM}-->${RESET} ${GRAY_LIGHT}BM_TITLE ${GRAY_DARK}${BOLD}[BM_TAGS]${RESET}\n${UNDERLINE}${DIM}BM_URL${RESET} ${GRAY_DARK}(BM_MD5)${RESET} - ${GRAY_DARK}Added: BM_DATE${RESET} - ${GRAY_DARK}Picture: BM_PICTURE${RESET}}" 143 | 144 | # _BM_PRINT_SCHEME : If set to no, bm will remove scheme from URL printing 145 | export _BM_PRINT_SCHEME=${_BM_PRINT_SCHEME:=true} 146 | 147 | # _BM_SEARCH_IGNORECASE : Ignore case if set when searching (overrided by -i) 148 | export _BM_SEARCH_IGNORECASE=${_BM_SEARCH_IGNORECASE:=false} 149 | } 150 | 151 | # slug creates a friendly URL like 'hello-world' 152 | slug() { 153 | iconv -f utf8 -t ascii//TRANSLIT | tr -cs '[:alnum:]\n' - | tr '[:upper:]' '[:lower:]' | sed 's|^-*||;s|-*$||' 154 | } 155 | 156 | 157 | 158 | 159 | # version 160 | RELEASE='35412a6' 161 | VERSION='0.6.7' 162 | 163 | # 164 | # Output usage info 165 | # 166 | 167 | usage() { 168 | if [ -z "${1:-}" ]; then 169 | cat <<EOF 170 | 171 | Usage: ${0} [modifier(s)] command [option(s)] 172 | 173 | Commands : 174 | ========== 175 | -h Print this help 176 | -H Print help for legacy usage 177 | -v/-V Print the version/And the short commit name 178 | -a 'URL' Add the URL to bookmark file 179 | Options for -a 180 | -t "TagList" Tags are sparated by a comma , 181 | -T "Title" Title for this URL (if empty and allowed Title 182 | downloaded) 183 | -A "accel" Accelerator when search for URLs (start with Accel) 184 | Default is an autoincrement index 185 | -F Force the bookmark to be created (even if duplicate 186 | or invalid) 187 | -p Force the screenshot to be taken (config dependant) 188 | 189 | -l List all URLs (default action, same thing as calling bm without args) 190 | Options for -l 191 | -z Use the alternate print list 192 | -n Sort the results by date 193 | -N Sort the results by date (reverse) 194 | 195 | -s 'object' Search for bookmarks 196 | Options for -s 197 | -i Incensitive case search 198 | -z Use the alternate print list 199 | -n Sort the results by date 200 | -N Sort the results by date (reverse) 201 | Objects are 202 | :string Search in accelerator list 203 | +string Search in tags list 204 | =string Search in MD5 list 205 | /string Search in URL list 206 | string Search in full test 207 | 208 | -o 'object' Search for bookmarks and open it (use the same argument as for -s) 209 | Options for -o 210 | -i Incensitive case search 211 | -O If more than one answer force the first bookmark to be open 212 | -Y If more than one answer force ALL bookmarks to be open 213 | 214 | -x 'object' Search for bookmarks and copy it to clipboard (use the same argument as for -s) 215 | Options for -x 216 | -i Incensitive case search 217 | -X If more than one answer force the first bookmark to be copied 218 | -Y If more than one answer force ALL bookmarks to be copied 219 | 220 | -r 'object' Search for bookmarks and Print the recorded associated picture (use the same argument as for -s) 221 | Options for -r 222 | -i Incensitive case search 223 | -O If more than one answer force the first bookmark to have its picture printed 224 | -Y If more than one answer force ALL bookmarks to have their picture printed 225 | 226 | -d 'URL' or Delete the URL from bookmark file 227 | md5sum or 228 | 'URL part' Options for -d 229 | -D Delete first occurence only 230 | -F Force the bookmark to be deleted (even if duplicate) 231 | -p Delete the associated picture (no trash available) 232 | 233 | -g Generate a HTML page with all bookmarks 234 | If used more than once, generate a page per tag 235 | Options for -g 236 | -G "filename" If g==1 then generate and use this filename to generate page 237 | -O Open the file when generated 238 | 239 | -P 'object' Generate all Non existant picture (check done for all URL in bm), if none argument. 240 | If an argument is given (use the same argument as for -s) only the results will have a picture. 241 | Options for -P 242 | -F Force the picture to be taken again (even if already exists). 243 | 244 | -q 'object' Connect to the URL to replace the existing Title by the downloaded one. 245 | Options for -q 246 | -i Incensitive case search 247 | -O If more than one answer force the first bookmark to have its title downloaded 248 | -Y If more than one answer force ALL bookmarks to have their title downloaded 249 | 250 | -L List all tags 251 | 252 | -C Print the color table (usefull for configuration) 253 | 254 | -E Open the bm.lnk with your \$EDITOR 255 | 256 | -S Show statistics about bookmarks/tags (and also configuration) 257 | Options for -S 258 | -p Print the list of orphaned Pictures 259 | 260 | Modifiers : 261 | =========== 262 | -c 'file' Use this configuration file instead of the default one 263 | 264 | -b 'file' Use this bookmark file instead of the default one 265 | 266 | -w 'directory' Use this directory to find default configuration file and bookmark file instead of the default one 267 | EOF 268 | else 269 | cat <<EOF 270 | 271 | Old Legacy usage still available : 272 | Usage: bm [options] [cmd] 273 | 274 | Commands: 275 | 276 | # add a bookmark with the given url, description, and optional tags 277 | $ bm add <url> [desc] [tag...] [accelerator] 278 | 279 | # open the first bookmark matching <query> 280 | $ bm open <query> 281 | $ bm <query> 282 | 283 | # search the bookmarks via full-text <query> 284 | $ bm search <query> 285 | 286 | # list tags 287 | $ bm tags 288 | 289 | # list bookmarks available 290 | $ bm list 291 | $ bm ls 292 | $ bm 293 | 294 | # display statistics about the bookmarks 295 | $ bm statistics 296 | $ bm stats 297 | 298 | # view bookmark screenshots in your default browser 299 | $ bm view design 300 | $ bm view 301 | 302 | # clear all bookmarks (now deprecated). Use -d instead. 303 | $ bm clear 304 | 305 | Options: 306 | 307 | -V output bm version 308 | -h output help information for new parameters 309 | -H output this help information 310 | 311 | 312 | EOF 313 | fi 314 | } 315 | 316 | getAccelMax() { 317 | # $2 ~ /^[[:SPACE:]]*:[[:SPACE:]]*[0-9][[:SPACE:]]*+$/ { n=gensub(/:([0-9])+/, "\\1", "g", $2); if (n>m) m=n; } 318 | # awk -F'|' ' 319 | # BEGIN { m=0; } 320 | # $0 !~ /^[ ]*#/ && $2 ~ /^[:space:]*:[:space:]*[0-9]+[:space:]*$/ { sub(/:+/, "", $2); if ($2>m) m=$2; } 321 | # END { print m+1; } 322 | # ' "${_BM_BOOKMARK_FILE}" 323 | while read a; do 324 | (( ${a:=0} >= ${_max:=0} )) && (( _max=${a}+1 )) 325 | done <<< "$( awk -F'|' '$0 !~ /^[ ]*#/ && $3 ~ /^[:space:]*:[:space:]*[0-9]+[:space:]*$/ { sub(/:+/, "", $3); print $3; }' "${_BM_BOOKMARK_FILE}")" 326 | echo -n "${_max}" 327 | } 328 | 329 | backupBm() { 330 | if [ "${_BM_BOOKMARK_BACKUP,,}" = 'true' ]; then 331 | while [ ${count:=${_BM_BOOKMARK_BACKUP_VERSION}} -gt 0 ]; do 332 | cp -- "${_BM_BOOKMARK_BACKUP_FILE}.$(( count-1 ))" "${_BM_BOOKMARK_BACKUP_FILE}.$(( count-- ))" 2>&1 >/dev/null 333 | done 334 | cp -- "${_BM_BOOKMARK_FILE}" "${_BM_BOOKMARK_BACKUP_FILE}.0" 335 | fi 336 | } 337 | 338 | titleDl() { 339 | if command -v hxselect &>/dev/null ; then 340 | curl -Lks "${1:-}" 2>&1 | hxselect -ic title 2>/dev/null 341 | else 342 | curl -Lks "${1:-}" 2>&1 | sed '/<title>/I!d;/<\/title>/I!d;s;^[[:space:]]*<title>\([^<]*\)<.*;\1;i' 343 | fi 344 | } 345 | 346 | saveUrl() { 347 | [[ "${__url}" =~ ^[[:space:]]*(f|ht)tps*://.*$ ]] || { 348 | if [ ${__F:=0} -eq 0 ]; then 349 | die "Your URL seems invalid '${__url}'. Use -F to force." 350 | else 351 | echo "Force adding invalid URL" >&2 352 | fi 353 | } 354 | local _sum="$(${_BM_CMD_MD5} <<< "${__url}")" 355 | if [ "${_BM_DUPS_DETECT,,}" = 'true' ]; then 356 | if [ ! -z "$(awk -F '|' '$0 !~ /^[ ]*#/ && $1 ~ /'"${_sum%% *}"'/' "${_BM_BOOKMARK_FILE}")" ]; then 357 | if [ ${__F:=0} -eq 0 ]; then 358 | die "URL is already in the Bookmark file" 359 | else 360 | echo "Force adding duplicate URL" >&2 361 | fi 362 | fi 363 | fi 364 | if [ "${_BM_GET_PAGE_TITLE,,}" = 'true' -a -z "${__T:=}" ]; then 365 | # if [ $( command -v hxselect &>/dev/null ) ]; then 366 | # __T="$( curl -Lks "${__url}" 2>&1 | hxselect -ic title )" 367 | # else 368 | # __T="$( curl -Lks "${__url}" 2>&1 | sed '/<title>/I!d;/<\/title>/I!d;s;^[[:space:]]*<title>\([^<]*\)<.*;\1;i' )" 369 | # fi 370 | __T="$( titleDl "${__url}" )" 371 | fi 372 | [[ ! -z "${__T:=}" ]] && __T="${__T//\|/\\|}" 373 | backupBm 374 | [[ -z "${__T:=}" ]] && __T="$(slug <<< "${__url}")" # If no title => slug the url 375 | [[ -z "${__t:=}" ]] && __t='default' # Default tag is default 376 | [[ -z "${__A:=}" ]] && __A="$(getAccelMax)" 377 | [[ "${__A:0:1}" != ':' ]] && __A=":${__A}" # If no accel => Add a number 378 | echo "${_sum%% *}|$(date '+%FT%TZ')|${__A}|${__url}|${__T}|${__t}" >> "${_BM_BOOKMARK_FILE}" || die "Insert aborted into '${_BM_BOOKMARK_FILE}' !" 379 | echo "${__url} inserted into '${_BM_BOOKMARK_FILE}'" 380 | [[ ! -f "${_BM_SCREENSHOT_DIRECTORY}/${_sum%% *}.png" || ${__F:=0} -eq 1 ]] && { screenshot_take "${_BM_SCREENSHOT_DIRECTORY}/${_sum%% *}.png" "${__url}" & } 381 | [[ "${_BM_SCREENSHOT_WAIT,,}" = 'true' ]] && wait 382 | search_bookmarks "${__A}" 383 | } 384 | 385 | # 386 | # manage each line to print it 387 | # 388 | 389 | readLines() { 390 | IFS='|' 391 | while read m d a u T t; do 392 | _line="${_BM_PRINT_LINE}" 393 | [[ ${__z:=0} -eq 1 ]] && _line="${_BM_PRINT_LINE_ALTERNATIVE}" 394 | _line="${_line//BM_MD5/$m}" 395 | if [ "${_BM_PRINT_SCHEME,,}" = 'false' ]; then 396 | u="$(sed 's/^[[:space:]]*\(f\|ht\)tps*:\/\///' <<< "${u}")" 397 | fi 398 | _line="${_line//BM_URL/$u}" 399 | _line="${_line//BM_TITLE/$T}" 400 | _line="${_line//BM_TAGS/$t}" 401 | _line="${_line//BM_ACCEL/${a:=No-Accelerator}}" 402 | _line="${_line//BM_DATE/${d}}" 403 | local _pict="$(stat -c '%y' "${_BM_SCREENSHOT_DIRECTORY}/${m}.png" 2>/dev/null)" 404 | [[ ! -z "${_pict}" ]] && _pict="$(date '+%FT%TZ' --date "${_pict}")" 405 | _line="${_line//BM_PICTURE/${_pict:=None}}" 406 | echo -e "${_line}\n" 407 | done 408 | } 409 | 410 | # 411 | # List all bookmarks 412 | # 413 | 414 | list_bookmarks() { 415 | [[ ${__n:=0} -eq 1 ]] && { awk '$0 !~ /^[ ]*#/' "${_BM_BOOKMARK_FILE}" | sort -t'|' -k2 | readLines; return; } 416 | [[ ${__N:=0} -eq 1 ]] && { awk '$0 !~ /^[ ]*#/' "${_BM_BOOKMARK_FILE}" | sort -t'|' -k2 -r | readLines; return; } 417 | awk '$0 !~ /^[ ]*#/' "${_BM_BOOKMARK_FILE}" | readLines 418 | } 419 | 420 | # 421 | # Search all bookmarks with <query> 422 | # 423 | search() { 424 | local _s='' 425 | [[ -z "${1:-}" ]] && list_bookmarks && return 426 | case "${1:0:1}" in 427 | :) _s=3; _ss=0 ;; # Accelerator 428 | +) _s="NF"; _ss=1 ;; # Tags 429 | =) _s=1; _ss=1 ;; # MD5 part 430 | /) _s=4; _ss=1 ;; # URL part 431 | *) _s=0; _ss=0 ;; # full text search 432 | esac 433 | [[ "${_BM_SEARCH_IGNORECASE,,}" = 'true' || ${__i:=0} -eq 1 ]] && local _ign=1 434 | awk -F'|' -vIgn=${_ign:=0} ' 435 | BEGIN { 436 | if (Ign == 1) { s=tolower("'"${1:${_ss}}"'"); } else { s="'"${1:${_ss}}"'"; } 437 | } 438 | $0 !~ /^[ ]*#/ && (Ign == 0 && $'"${_s}"' ~ s) || (Ign ==1 && tolower($'"${_s}"') ~ s) {print $0;} 439 | ' "${_BM_BOOKMARK_FILE}" 440 | 441 | } 442 | search_bookmarks() { 443 | [[ ${__n:=0} -eq 1 ]] && { search "${@}" | sort -t'|' -k2 | readLines; return; } 444 | [[ ${__N:=0} -eq 1 ]] && { search "${@}" | sort -t'|' -k2 -r | readLines; return; } 445 | search "${@}" | readLines 446 | } 447 | 448 | # 449 | # Open first bookmark matching <query> 450 | # 451 | 452 | recorded_picture() { 453 | local _lines="$(search "${@}")" 454 | if [ "${_BM_ASK_BEFORE_OPEN,,}" = 'true' -a ${__O:=0} -eq 0 -a ${__Y:=0} -eq 0 ]; then 455 | if [ $(wc -l <<< "${_lines}") -gt 1 ]; then 456 | read -p"More than one URL found. Open all Pictures ? [Y/N] : " -n1 _answer 457 | [[ "${_answer,,}" != 'y' ]] && die "\nUse -O to force the first URL or refine your search" 458 | fi 459 | fi 460 | local _all='' 461 | echo '' 462 | while read _nl; do 463 | readLines <<< "${_nl}" 464 | if [ "${_BM_OPEN_ALL,,}" = 'true' -o ${__Y:=0} -eq 1 ]; then 465 | _all="${_BM_SCREENSHOT_DIRECTORY}/$(awk -F'|' '{print $1}' <<< "${_nl}").png ${_all}" 466 | else 467 | "${_BM_CMD_IMAGE_OPEN}" "${_BM_SCREENSHOT_DIRECTORY}/$(awk -F'|' '{print $1}' <<< "${_nl}").png" 468 | [[ "${_BM_OPEN_FIRST,,}" = 'true' || ${__O:=0} -eq 1 ]] && exit 0 469 | fi 470 | done <<< "$(echo -e "${_lines}")" 471 | [[ "${_BM_OPEN_ALL,,}" = 'true' || ${__Y:=0} -eq 1 ]] && "${_BM_CMD_IMAGE_OPEN}" "${_all}" 472 | } 473 | 474 | download_title() { 475 | local _lines="$(search "${@}")" 476 | if [ "${_BM_ASK_BEFORE_OPEN,,}" = 'true' -a ${__O:=0} -eq 0 -a ${__Y:=0} -eq 0 ]; then 477 | if [ $(wc -l <<< "${_lines}") -gt 1 ]; then 478 | read -p"More than one URL found. Download Title for all URLs ? [Y/N] : " -n1 _answer 479 | [[ "${_answer,,}" != 'y' ]] && die "\nUse -O to force the first URL or refine your search" 480 | fi 481 | fi 482 | local _all='' 483 | echo '' 484 | while read _nl; do 485 | readLines <<< "${_nl}" 486 | local u="$(awk -F'|' '{print $4}' <<< "${_nl}")" 487 | if [ "${_BM_OPEN_ALL,,}" = 'true' -o ${__Y:=0} -eq 1 ]; then 488 | echo "${u} --> $( titleDl "${u}" )" 489 | else 490 | echo "${u} --> $( titleDl "${u}" )" 491 | [[ "${_BM_OPEN_FIRST,,}" = 'true' || ${__O:=0} -eq 1 ]] && exit 0 492 | fi 493 | done <<< "$(echo -e "${_lines}")" 494 | } 495 | 496 | open_bookmark() { 497 | local _lines="$(search "${@}")" 498 | if [ "${_BM_ASK_BEFORE_OPEN,,}" = 'true' -a ${__O:=0} -eq 0 -a ${__Y:=0} -eq 0 ]; then 499 | if [ $(wc -l <<< "${_lines}") -gt 1 ]; then 500 | read -p"More than one URL found. Open all ? [Y/N] : " -n1 _answer 501 | [[ "${_answer,,}" != 'y' ]] && die "\nUse -O to force the first URL or refine your search" 502 | fi 503 | fi 504 | local _all='' 505 | while read _nl; do 506 | readLines <<< "${_nl}" 507 | if [ "${_BM_OPEN_ALL,,}" = 'true' -o ${__Y:=0} -eq 1 ]; then 508 | _all="$(awk -F'|' '{print $4}' <<< "${_nl}") ${_all}" 509 | else 510 | "${_BM_CMD_OPEN}" "$(awk -F'|' '{print $4}' <<< "${_nl}")" 511 | [[ "${_BM_OPEN_FIRST,,}" = 'true' || ${__O:=0} -eq 1 ]] && exit 0 512 | fi 513 | done <<< "$(echo -e "${_lines}")" 514 | [[ "${_BM_OPEN_ALL,,}" = 'true' || ${__Y:=0} -eq 1 ]] && "${_BM_CMD_OPEN}" "${_all}" 515 | } 516 | 517 | copy_bookmark() { 518 | local _lines="$(search "${@}")" 519 | if [ "${_BM_ASK_BEFORE_OPEN,,}" = 'true' -a ${__X:=0} -eq 0 -a ${__Y:=0} -eq 0 ]; then 520 | if [ $(wc -l <<< "${_lines}") -gt 1 ]; then 521 | read -p"More than one URL found. Copy all ? [Y/N] : " -n1 _answer 522 | [[ "${_answer,,}" != 'y' ]] && die "\nUse -X to force the first URL or refine your search" 523 | fi 524 | fi 525 | local _all='' 526 | while read _nl; do 527 | readLines <<< "${_nl}" 528 | if [ "${_BM_OPEN_ALL,,}" = 'true' -o ${__Y:=0} -eq 1 ]; then 529 | _all="$(awk -F'|' '{print $4}' <<< "${_nl}") ${_all}" 530 | else 531 | awk -F'|' '{print $4}' <<< "${_nl}" | "${_BM_CMD_COPY}" 532 | awk -F'|' '{print $4}' <<< "${_nl}" | "${_BM_CMD_COPY}" -b 533 | [[ "${_BM_OPEN_FIRST,,}" = 'true' || ${__X:=0} -eq 1 ]] && exit 0 534 | fi 535 | done <<< "$(echo -e "${_lines}")" 536 | [[ "${_BM_OPEN_ALL,,}" = 'true' || ${__Y:=0} -eq 1 ]] && "${_BM_CMD_COPY}" <<< "${_all}" 537 | [[ "${_BM_OPEN_ALL,,}" = 'true' || ${__Y:=0} -eq 1 ]] && "${_BM_CMD_COPY}" -b <<< "${_all}" 538 | } 539 | 540 | delete_bookmark() { 541 | [[ -z "${@//[ ]/}" ]] && die "You MUST give an argument !" 542 | local _lines="$(search "${@}")" 543 | if [ "${_BM_DELETE_ALLOWED,,}" = 'true' ]; then 544 | while read _nl; do readLines <<< "${_nl}"; done <<< "$(echo -e "${_lines}")" 545 | if [ "${_BM_ASK_BEFORE_OPEN,,}" = 'true' -a ${__D:=0} -eq 0 -a ${__Y:=0} -eq 0 ]; then 546 | if [ $(wc -l <<< "${_lines}") -ge 1 ]; then 547 | read -p"You're about to delete entry(ies). Ready ? [Y/N] : " -n1 _answer 548 | [[ "${_answer,,}" != 'y' ]] && die "\nUse -D to force the backup if not configured." 549 | echo '' 550 | fi 551 | fi 552 | backupBm 553 | local _all='' 554 | while read _nl; do 555 | if [ "${_BM_DELETE_TO_FILE,,}" = 'true' -o ${__D:=0} -eq 1 ]; then 556 | echo "${_nl}" >> "${_BM_DELETE_FILE}" 557 | fi 558 | [[ "${_BM_DELETE_PICTURE,,}" = 'true' || ${__p:=0} -eq 1 ]] && rm -f -- "${_BM_SCREENSHOT_DIRECTORY}/${_nl%%|*}.png" 559 | IFS='|' read m d a u T t <<< "${_nl}" 560 | sed -i -e '/^'"${m}.*${u//\//\\/}.*${t//\//\\/}"'$/d' "${_BM_BOOKMARK_FILE}" 561 | done <<< "$(echo -e "${_lines}")" 562 | else 563 | die "You're not allowed to delete entries. Change the _BM_DELETE_ALLOWED to true !" 564 | fi 565 | } 566 | 567 | edit_bookmark() { 568 | echo -e "You're about to open your '${_BM_BOOKMARK_FILE}' file with your \$EDITOR.\n\n/!\ Press any key to continue, or CTRL+C to abort. /!\ " 569 | read -n1 toto 570 | ${EDITOR:=vi} "${_BM_BOOKMARK_FILE}" 571 | } 572 | 573 | # 574 | # Diplay some statistics about the bookmarks 575 | # 576 | stats() { 577 | echo "===== Configuration =====" 578 | echo "Bookmark file : ${_BM_BOOKMARK_FILE}" 579 | echo "Config file : ${_BM_CONFIG_FILE}$([[ ! -e "${_BM_CONFIG_FILE}" ]] && echo " (but doesn't exist)")" 580 | echo "Trash file : ${_BM_DELETE_FILE}$([[ ! -e "${_BM_DELETE_FILE}" ]] && echo " (but doesn't exist)")" 581 | echo "Screenshot directory : ${_BM_SCREENSHOT_DIRECTORY}" 582 | echo "Backup file(s) : ${_BM_BOOKMARK_BACKUP_FILE}*" 583 | for i in "${_BM_BOOKMARK_BACKUP_FILE}"*; do 584 | echo " ${i}" 585 | done 586 | echo -e "\n===== Statistics =====" 587 | readarray -t lines < "${_BM_BOOKMARK_FILE}" 588 | echo "# of Bookmarks : ${#lines[@]}" 589 | echo "# of Duplicate : $(awk -F'|' '$0 !~ /^[ ]*#/ {print $1}' "${_BM_BOOKMARK_FILE}" |sort |uniq -d |wc -l)" 590 | local tags="$(awk -F'|' '$0 !~ /^[ ]*#/ {print $NF}' "${_BM_BOOKMARK_FILE}" | sed -e 's/\([[:space:]]*,[[:space:]]*\)/\n/g')" 591 | 592 | echo "# of tags : $( sort -u <<< "${tags,,}" |wc -l)" 593 | echo "Top 14 tags used :" 594 | local nli=0;local pa=0 595 | ( 596 | sort <<< "${tags,,}" | uniq -c | sort -nr | while read n t; do 597 | (( nli++ ));[[ ${nli} -gt 7 ]] && nli=1 && echo '' 598 | (( pa++ ));[[ ${pa} -gt 14 ]] && break 599 | echo -n "${t// / }:${n} " 600 | done 601 | echo '' 602 | ) | column -t -x -c 7 603 | echo "# of Pictures : $(ls -1 "${_BM_SCREENSHOT_DIRECTORY}"/*.png |wc -l) [# of files in ${_BM_SCREENSHOT_DIRECTORY}:$(ls -1 "${_BM_SCREENSHOT_DIRECTORY}"/* |wc -l)]" 604 | echo "All Pictures size : $(du -sh "${_BM_SCREENSHOT_DIRECTORY}" | awk '{print $1}')" 605 | local orphaned="$( cd "${_BM_SCREENSHOT_DIRECTORY}" && for i in *; do [[ -z "$(sed -e '/'"${i%%.*}"'/!d' "${_BM_BOOKMARK_FILE}")" ]] && ((orph++)); done; echo "${orph:=0}" )" 606 | local nopics="$( while read i; do [[ ! -f "${_BM_SCREENSHOT_DIRECTORY}/${i%%|*}.png" ]] && ((nopics++)); done <<< ${lines[@]}; echo "${nopics:=0}" )" 607 | echo "Bookmark Without Pic : ${nopics}" 608 | echo "Orphaned pictures : ${orphaned}" 609 | [[ ${__p:=0} -eq 1 ]] && { echo -e "\n===== Orphaned ====="; echo "List of orphaned pictures :"; cd "${_BM_SCREENSHOT_DIRECTORY}" && for i in *; do [[ -z "$(sed -e '/'"${i%%.*}"'/!d' "${_BM_BOOKMARK_FILE}")" ]] && echo " - ${_BM_SCREENSHOT_DIRECTORY}/${i} [Trashed URL should be: $(awk -F'|' 'BEGIN{l="Unknown"} ($1 ~ /'"${i%%.*}"'/) {l=$4;} END {print l}' "${_BM_DELETE_FILE}")]"; done; }; 610 | } 611 | 612 | # 613 | # Output tags. 614 | # 615 | 616 | list_tags() { 617 | local tags="$(awk -F'|' '$0 !~ /^[ ]*#/ {print $NF}' "${_BM_BOOKMARK_FILE}" | sed -e 's/\([[:space:]]*,[[:space:]]*\)/\n/g')" 618 | local nli=0 619 | ( 620 | sort <<< "${tags,,}" | uniq -c | sort -nr | while read n t; do 621 | (( nli++ ));[[ ${nli} -gt 7 ]] && nli=1 && echo '' 622 | echo -n "${t// / }:${n} " 623 | done 624 | echo '' 625 | ) | column -t -x -c 7 626 | } 627 | 628 | # 629 | # Stylesheet 630 | # 631 | 632 | style() { 633 | cat <<EOF 634 | <style type="text/css"> 635 | * { 636 | -webkit-box-sizing: border-box; 637 | -moz-box-sizing: border-box; 638 | box-sizing: border-box; 639 | } 640 | body { 641 | padding: 50px 0 5px 50px; 642 | background: #1f1f1f url(${_BM_SCREENSHOT_DIRECTORY}/black-Linen.png); 643 | font: 12px "Helvetica Neue", Helvetica, Arial, sans-serif; 644 | } 645 | .bm { 646 | position: relative; 647 | float: left; 648 | margin: 15px; 649 | padding: 1px; 650 | opacity: 1; 651 | border: 15px solid black; 652 | border-radius: 5px; 653 | -webkit-border-radius: 5px; 654 | -moz-border-radius: 5px; 655 | -webkit-transition: -webkit-box-shadow 600ms; 656 | -moz-transition: -webkit-box-shadow 600ms; 657 | -webkit-box-shadow: 0 0 1px 0 #555, 0 0 10px rgba(0,0,0,.5); 658 | -moz-box-shadow: 0 0 1px 0 #555, 0 0 10px rgba(0,0,0,.5); 659 | overflow: hidden; 660 | } 661 | .bm:hover { 662 | -webkit-box-shadow: 0 0 40px #1ab0ff 663 | , 0 0 3px #06bdff 664 | , 0 1px 1px #4ee2ff 665 | , 0 1px 0 #fff; 666 | -moz-box-shadow: 0 0 40px #1ab0ff 667 | , 0 0 3px #06bdff 668 | , 0 1px 1px #4ee2ff 669 | , 0 1px 0 #fff; 670 | } 671 | .bm:hover img { 672 | opacity: 1; 673 | } 674 | .bm img { 675 | width: 200px; 676 | height: 150px; 677 | opacity: .5; 678 | border-radius: 5px; 679 | -webkit-border-radius: 5px; 680 | -moz-border-radius: 5px; 681 | -webkit-transition: opacity 200ms; 682 | -moz-transition: opacity 200ms; 683 | } 684 | .bm p { 685 | margin: 0; 686 | padding: 10px; 687 | width: 100%; 688 | background: rgba(0,0,0,.75); 689 | position: absolute; 690 | left: 0; 691 | color: white; 692 | letter-spacing: 1px; 693 | bottom: -50px; 694 | -webkit-font-smoothing: antialiased; 695 | -webkit-transition: bottom 200ms ease-in; 696 | } 697 | .bm:hover p { 698 | bottom: 0; 699 | } 700 | </style> 701 | EOF 702 | } 703 | 704 | # 705 | # Generate bookmark screenshots 706 | # 707 | 708 | screenshot_take() { 709 | if [ "${_BM_SCREENSHOT_GET,,}" = 'true' -o ${__p:=0} -eq 1 ]; then 710 | [[ ! -d "${_BM_SCREENSHOT_DIRECTORY}" ]] && { mkdir -p "${_BM_SCREENSHOT_DIRECTORY}" || die "Can't create thumbnail directory." ; } 711 | [[ ! -z "${_BM_CMD_PRE_CAPTURE}" ]] && { local _pre="${_BM_CMD_PRE_CAPTURE//\{FILE\}/${1}}"; _pre="${_pre//\{URL\}/${2}}"; ${_pre} ; } 712 | local _cmd="${_BM_CMD_CAPTURE//\{FILE\}/${1}}"; _cmd="${_cmd//\{URL\}/${2}}"; 713 | local _args="${_BM_CMD_CAPTURE_ARGS//\{FILE\}/${1}}"; _args="${_args//\{URL\}/${2}}"; 714 | eval ${_cmd} ${_args} 715 | [[ ! -z "${_BM_CMD_POST_CAPTURE}" ]] && { local _post="${_BM_CMD_POST_CAPTURE//\{FILE\}/${1}}"; _post="${_post//\{URL\}/${2}}"; ${_post} ; } 716 | fi 717 | } 718 | 719 | picturize() { 720 | if [ -z "${1:-}" ]; then 721 | awk -F'|' '$0 !~ /^[ ]*#/ {print $1,$4;}' "${_BM_BOOKMARK_FILE}" | while read m u; do 722 | [[ ! -f "${_BM_SCREENSHOT_DIRECTORY}/${m}.png" || ${__F:=0} -eq 1 ]] && { screenshot_take "${_BM_SCREENSHOT_DIRECTORY}/${m}.png" "${u}" & } 723 | [[ "${_BM_SCREENSHOT_WAIT,,}" = 'true' ]] && wait 724 | done 725 | else 726 | local _lines="$(search "${@}")" 727 | if [ "${_BM_ASK_BEFORE_OPEN,,}" = 'true' -a ${__O:=0} -eq 0 -a ${__Y:=0} -eq 0 ]; then 728 | if [ $(wc -l <<< "${_lines}") -gt 1 ]; then 729 | read -p"More than one URL found. Open all ? [Y/N] : " -n1 _answer 730 | [[ "${_answer,,}" != 'y' ]] && die "\nUse -O to force the first URL or refine your search" 731 | fi 732 | fi 733 | local _all='' 734 | while read _nl; do 735 | readLines <<< "${_nl}" 736 | if [ "${_BM_OPEN_ALL,,}" = 'true' -o ${__Y:=0} -eq 1 ]; then 737 | IFS='|' read m d a u b <<< "${_nl}" 738 | screenshot_take "${_BM_SCREENSHOT_DIRECTORY}/${m}.png" "${u}" & 739 | else 740 | IFS='|' read m d a u b <<< "${_nl}" 741 | screenshot_take "${_BM_SCREENSHOT_DIRECTORY}/${m}.png" "${u}" & 742 | [[ "${_BM_OPEN_FIRST,,}" = 'true' || ${__O:=0} -eq 1 ]] && exit 0 743 | fi 744 | done <<< "$(echo -e "${_lines}")" 745 | fi 746 | } 747 | 748 | bookmark_generator() { 749 | [[ ! -f "${_BM_SCREENSHOT_DIRECTORY}/black-Linen.png" && -f "/usr/share/bm/black-Linen.png" ]] && cp "/usr/share/bm/black-Linen.png" "${_BM_SCREENSHOT_DIRECTORY}/black-Linen.png" 750 | echo "<!DOCTYPE html><html><head><meta charset="UTF-8"><title>bm v${VERSION} : all your bookmarks" > "${1:-${_BM_HTML_FILE}}" 751 | style >> "${1:-${_BM_HTML_FILE}}" 752 | echo "" >> "${1:-${_BM_HTML_FILE}}" 753 | # search "${2:-}" | while IFS='|' read m a u T t d; do 754 | awk '$0 !~ /^[ ]*#/' "${_BM_BOOKMARK_FILE}" | while IFS='|' read m d a u T t; do 755 | echo "
756 | ${u} 757 |

${T}
View image

758 |
" >> "${1:-${_BM_HTML_FILE}}" 759 | done 760 | echo "" >> "${1:-${_BM_HTML_FILE}}" 761 | [[ ${__O:=0} -eq 1 ]] && "${_BM_CMD_OPEN}" "${1:-${_BM_HTML_FILE}}" 762 | } 763 | 764 | # 765 | # die print message to stderr and exit 766 | # 767 | 768 | die() { 769 | echo -e "${@}" >&2 770 | exit 1 771 | } 772 | 773 | 774 | # 775 | # checkBinaries check the script is able to run and give hints 776 | # 777 | 778 | checkBinaries() { 779 | if [ ${#} -ne 0 ]; then 780 | local cmdErr="${@}" 781 | else 782 | local cmdErr="sed awk date iconv cat curl ${_BM_CMD_OPEN} ${_BM_CMD_MD5} column" 783 | fi 784 | set ${cmdErr} 785 | while [ ${#} -ne 0 ]; do 786 | if ! command -v "${1:-}" &>/dev/null; then 787 | echo "command not found: ${1}" >&2 788 | local rc=1 789 | fi 790 | shift 791 | done 792 | [[ ${rc:=0} -ne 0 ]] && die "At least one command is missing. Please install it before using bm." 793 | # Checking sed 794 | local rc=1 795 | [[ ! -f "/tmp/sedtest.$$" ]] && \ 796 | echo -n 'toto' > "/tmp/sedtest.$$" && \ 797 | sed -i.bak -e 's;^toto$;tata;' "/tmp/sedtest.$$" && \ 798 | [[ -f "/tmp/sedtest.$$.bak" ]] && \ 799 | grep -q "tata" "/tmp/sedtest.$$" && \ 800 | rc=0 && \ 801 | rm -f "/tmp/sedtest.$$" "/tmp/sedtest.$$.bak" 802 | [[ ${rc} -ne 0 ]] && die "sed seems to not handle -i argument properly, please check" 803 | } 804 | 805 | # 806 | # defineColors generate the variables to use to colorize the output 807 | # 808 | 809 | defineColors() { 810 | export BLACK="\e[30m"; export BLACK_LIGHT="\e[90m"; export GRAY_DARK="${BLACK_LIGHT}" 811 | export RED="\e[31m"; export RED_LIGHT="\e[91m" 812 | export GREEN="\e[32m"; export GREEN_LIGHT="\e[92m" 813 | export YELLOW="\e[33m"; export YELLOW_LIGHT="\e[93m" 814 | export BLUE="\e[34m"; export BLUE_LIGHT="\e[94m" 815 | export MAGENTA="\e[35m"; export MAGENTA_LIGHT="\e[95m" 816 | export CYAN="\e[36m"; export CYAN_LIGHT="\e[96m" 817 | export GRAY="\e[37m"; export GRAY_LIGHT="\e[97m"; export WHITE="${GRAY_LIGHT}" 818 | 819 | export RESET="\e[0m" 820 | export BOLD="\e[1m"; export BOLD_RESET="\e[21m" 821 | export DIM="\e[2m"; export DIM_RESET="\e[22m" 822 | export UNDERLINE="\e[4m"; export UNDERLINE_RESET="\e[24m" 823 | export INVERT="\e[7m"; export INVERT_RESET="\e[27m" 824 | if [ ! -z "${1:-}" ]; then 825 | echo "Use the following colors to fit your needs :" 826 | ( 827 | echo -e "${RESET}${BLACK}BLACK${RESET} - ${BLACK_LIGHT}BLACK_LIGHT${RESET} - ${BOLD}${BLACK}BOLD BLACK${RESET} - ${DIM}${BLACK}DIM BLACK${RESET}" 828 | echo -e "${RESET}${RED}RED${RESET} - ${RED_LIGHT}RED_LIGHT${RESET} - ${BOLD}${RED}BOLD RED${RESET} - ${DIM}${RED}DIM RED${RESET}" 829 | echo -e "${RESET}${GREEN}GREEN${RESET} - ${GREEN_LIGHT}GREEN_LIGHT${RESET} - ${BOLD}${GREEN}BOLD GREEN${RESET} - ${DIM}${GREEN}DIM GREEN${RESET}" 830 | echo -e "${RESET}${YELLOW}YELLOW${RESET} - ${YELLOW_LIGHT}YELLOW_LIGHT${RESET} - ${BOLD}${YELLOW}BOLD YELLOW${RESET} - ${DIM}${YELLOW}DIM YELLOW${RESET}" 831 | echo -e "${RESET}${BLUE}BLUE${RESET} - ${BLUE_LIGHT}BLUE_LIGHT${RESET} - ${BOLD}${BLUE}BOLD BLUE${RESET} - ${DIM}${BLUE}DIM BLUE${RESET}" 832 | echo -e "${RESET}${MAGENTA}MAGENTA${RESET} - ${MAGENTA_LIGHT}MAGENTA_LIGHT${RESET} - ${BOLD}${MAGENTA}BOLD MAGENTA${RESET} - ${DIM}${MAGENTA}DIM MAGENTA${RESET}" 833 | echo -e "${RESET}${CYAN}CYAN${RESET} - ${CYAN_LIGHT}CYAN_LIGHT${RESET} - ${BOLD}${CYAN}BOLD CYAN${RESET} - ${DIM}${CYAN}DIM CYAN${RESET}" 834 | echo -e "${RESET}${GRAY}GRAY${RESET} - ${GRAY_LIGHT}GRAY_LIGHT${RESET} - ${BOLD}${GRAY}BOLD GRAY${RESET} - ${DIM}${GRAY}DIM GRAY${RESET}" 835 | echo -e "${RESET}${GRAY_DARK}GRAY_DARK${RESET} - ${WHITE}WHITE${RESET}" 836 | ) | column -t 837 | echo -e "You could also use the ${UNDERLINE}UNDERLINE, the ${INVERT}INVERT and the ${RESET}RESET variable. INVERT_RESET and UNDERLINE_RESET also available" 838 | exit 0 839 | fi 840 | } 841 | 842 | ############################################################################## 843 | # MAIN 844 | ############################################################################## 845 | 846 | ##################### TRANSITIONNAL ############################ 847 | _regex='^(help|version|tags|ls|list|search|open|add|view|stats|statistics|clear|colors)$' 848 | if [[ ${1:-} =~ ${_regex} ]]; then 849 | case "$1" in 850 | tags) __L=1 ;; 851 | ls|list) __l=1 ;; 852 | search) __s=1; __search="${@:2}" ;; 853 | open) __o=1; __open="${@:2}";; 854 | add) __a=1; __url="${2:-}"; __T="${3:-}"; __t="${4:-}"; __A="${5:-}";; 855 | view) __r=1; __search="${@:2}" ;; 856 | stats|statistics) __S=1 ;; 857 | clear) die "This now a deprecated feature. Use -d instead." ;; 858 | colors) __C=1;; 859 | help) usage 1;exit 0;; 860 | version) echo -n "${0} v${VERSION}";exit 0;; 861 | esac 862 | else 863 | #q -c config file 864 | # -C colors print ==> exit 865 | # -b bookmark file 866 | # -d delete 867 | # -D deletefile if set override _BM_DELETE_TO_FILE to true 868 | # -w working dir 869 | # -a add url =/= -l, -s, -S, -O, -o, -x, -X, -g, -C 870 | # -A Accelerator 871 | # -T title 872 | # -t tags 873 | # -s search 874 | # -S stats 875 | # -l list all url 876 | # -o open 877 | # -O open first 878 | # -x copy to clipboard 879 | # -X copy first URL 880 | # -h help 881 | # -H more help 882 | # -v version 883 | # -V more version ? 884 | # -g generate html file 885 | # -G use this file 886 | # -g -g generate 1 file per tags 887 | # used : AaBbCcDdE-F-GgHh-i----Ll--NnOoPp-q-rSsTt--Vv-wXxY--z---------- 888 | # available : ---------e-f----I-JjKk--Mm------Q-R-----Uu--W----yZ-0123456789 889 | while getopts ":a:A:b:c:d:G:o:P:q:r:s:t:T:w:x:BCDEFghHilLnNOpPSvVXYz" option; do 890 | case ${option} in 891 | a) __a=1; __url="${OPTARG}";; # Add url to bookmark 892 | A) __A="${OPTARG}";; # AcceleratoR 893 | b) __b="${OPTARG}";; # Bookmark file 894 | B) __B=1;; # Don't load the default config file 895 | c) __c="${OPTARG}";; # Config file 896 | C) __C=1;; # Print color table 897 | d) __d=1; __del="${OPTARG}";; # Config file 898 | D) __D=1;; # Print color table 899 | E) __E=1;; # Open the bm.lnk file with the $EDITOR 900 | F) __F=1;; # Force the add or delete or picture 901 | g) (( __g++ ));; # generate html file(s) 902 | G) __G=1; __file="${OPTARG}";; # Generate this file (only for g=1) 903 | h) usage; exit 0;; # Help 904 | H) usage 1; exit 0;; # Help 905 | i) __i=1;; # Ignore case when searching 906 | l) __l=1;; # List all bookmarks 907 | L) __L=1;; # List all tags 908 | n) __n=1;; # sort by date 909 | N) __N=1;; # sort by date (reverse) 910 | o) __o=1; __open="${OPTARG}";; # Open 911 | O) __O=1;; # Open First 912 | p) __p=1;; # Take a screenshot 913 | P) __P=1; __search="${OPTARG}";; # Take all screenshot 914 | q) __q=1; __search="${OPTARG}";; # Search 915 | r) __r=1; __search="${OPTARG}";; # Search 916 | s) __s=1; __search="${OPTARG}";; # Search 917 | S) __S=1;; # Print Statistics 918 | t) __t="${OPTARG}";; # tags for a URL 919 | T) __T="${OPTARG}";; # Title for a URL 920 | v|V) echo -n "${0} v${VERSION}"; [[ "${option}" = 'V' ]] && echo -n " [commit: ${RELEASE}]"; echo ''; exit 0;; 921 | w) __w="${OPTARG}";; # Working directory 922 | x) __x=1; __copy="${OPTARG}";; # Copy 923 | X) __X=1;; # Copy First 924 | Y) __Y=1;; # Open/copy All 925 | z) __z=1;; # Alternative print listing 926 | :) echo "Missing argument for '-${OPTARG}'" >&2 ; exit 1 ;; 927 | ?) echo "Argument unknown '-${OPTARG}'" >&2 ; exit 1 ;; # usage;; 928 | *) echo "Argument unknown '-${option}'" >&2 ; exit 1 ;; # usage;; 929 | esac 930 | done 931 | fi 932 | 933 | # Parsing args is done, Starting to work, so check if binaries are here 934 | checkBinaries 935 | 936 | # defineColors MUST be called before the config() or _BM_PRINT_LINE will be in trouble. 937 | defineColors 938 | # Before loading config, checking if working dir exist... 939 | if [ ! -z "${__w:=}" -a ! -d "${__w}" ]; then 940 | die "Working directory '${__w}' doesn't exist !" >&2 941 | fi 942 | # Loading config 943 | config "${__c}" 944 | [[ ! -z "${__b:=}" ]] && export _BM_BOOKMARK_FILE="${__b}" 945 | 946 | # Following config, we maybe not have to check the capture tool 947 | [[ ${_BM_CMD_CAPTURE_CHECK} ]] && checkBinaries "${_BM_CMD_CAPTURE}" 948 | 949 | # If no bookmark file exist, create one if allowed 950 | if [ ! -f "${_BM_BOOKMARK_FILE}" -a "${_BM_CREATE_BOOKMARK_FILE,,}" = 'true' ]; then 951 | # Remember fields : 1=md5, 2=date, 2=accel, 3=url, 4=title, 5=tags 952 | echo "bd8b3eff7fa82a0382a3e7576c5363b6|$(date '+%FT%TZ')|:bm|https://github.com/Flyounet/bm/|bm a cool enhanced bookmark tool for your console|default,shell" >> "${_BM_BOOKMARK_FILE}" 953 | echo "2981b5cae113491ddb18e0d51454f0d9|$(date '+%FT%TZ')|:bmtj|https://github.com/tj/bm/|The original bm : a cool bookmark tool for your console|default,shell" >> "${_BM_BOOKMARK_FILE}" 954 | fi 955 | 956 | # Starting to work with args. If none probably list... 957 | [[ ${#} -eq 0 && "${_BM_NO_ARGS_FORCE_HELP,,}" = 'true' ]] && { usage ; exit; } 958 | 959 | # Only one action at a time 960 | if [ $(( ${__a:=0} + ${__C:=0} + ${__d:=0} + ${__E:=0} + ${__g:=0} + ${__l:=0} + ${__L:=0} + ${__o:=0} + ${__P:=0} + ${__q:=0} + ${__r:=0} + ${__s:=0} + ${__S:=0} + ${__x:=0} )) -gt 1 ]; then 961 | echo "You have to choose between -a, -C, -d, -E, -g, -l, -L, -o, -P, -q, -r, -s, -S, -x" >&2 962 | echo "Use -h for help" >&2 963 | exit 0 964 | fi 965 | if [ $(( ${__O:=0} + ${__Y:=0} + ${__X:=0} )) -gt 1 ]; then 966 | echo "You have to choose between -O, -X, -Y" >&2 967 | echo "Use -h for help" >&2 968 | exit 0 969 | fi 970 | 971 | # Executing actions 972 | [[ ${__a} -eq 1 ]] && { saveUrl ; exit ; } 973 | [[ ${__C} -eq 1 ]] && { defineColors 1 ; exit ; } 974 | [[ ${__d} -eq 1 ]] && { delete_bookmark "${__del}"; exit ; } 975 | [[ ${__g} -ge 1 ]] && { bookmark_generator "${__file:=}" ''; exit ; } 976 | [[ ${__l} -eq 1 ]] && { search ; exit; } 977 | [[ ${__L} -eq 1 ]] && { list_tags ; exit; } 978 | [[ ${__o} -eq 1 ]] && { open_bookmark "${__open}" ; exit; } 979 | [[ ${__P} -eq 1 ]] && { picturize "${__search}" ; exit; } 980 | [[ ${__r} -eq 1 ]] && { recorded_picture "${__search}" ; exit; } 981 | [[ ${__q} -eq 1 ]] && { download_title "${__search}" ; exit; } 982 | [[ ${__s} -eq 1 ]] && { search_bookmarks "${__search}" ; exit; } 983 | [[ ${__S} -eq 1 ]] && { stats ; exit; } 984 | [[ ${__x} -eq 1 ]] && { copy_bookmark "${__copy}" ; exit; } 985 | [[ ${__E} -eq 1 ]] && { edit_bookmark ; exit; } 986 | search 987 | 988 | # GitHub @ Fri, 14 Oct 2016 22:30:47 +0200 : $Id: 46fe3b0647de7136b877dec1c34202b15807db2e $ 989 | -------------------------------------------------------------------------------- /licenses.txt: -------------------------------------------------------------------------------- 1 | ############################################################################## 2 | 3 | 4 | 5 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 6 | Version 2, December 2004 7 | 8 | Copyright (C) 2004 Sam Hocevar 9 | 10 | Everyone is permitted to copy and distribute verbatim or modified 11 | copies of this license document, and changing it is allowed as long 12 | as the name is changed. 13 | 14 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 15 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 16 | 17 | 0. You just DO WHAT THE FUCK YOU WANT TO. 18 | 19 | 20 | 21 | ############################################################################## 22 | 23 | 24 | 25 | Demerden Sie Sich License 26 | 27 | Version 1, 15 Mars 2010 28 | 29 | Copyright © 2010 Flyounet. 30 | 31 | Chacun est autorisé à copier et distribuer des copies conformes de ce document de licence, mais toute modification en est proscrite. 32 | DSSL : Demerden Sie Sich License 33 | Préambule : 34 | 35 | La Licence Démerdez-vous («Demerden Sie Sich License») est une licence libre, en «copyleft», destinée aux œuvres logicielles et d’autres types de travaux. Elle s'appuie sur des fondamentaux comme la Licence Lis ce Putain de Manuel ("Read This Fucking Manual License"). 36 | 37 | «Cette Licence» est auto-récursive, puisqu'elle est, elle même, assujetie à la «Demerden Sie Sich License». 38 | Termes et Conditions : 39 | Article 0. Définitions. 40 | 41 | «Cette Licence» se réfère à la version 1 de la «Demerden Sie Sich License» (le texte original en français). 42 | «Démerder», se réfère au sens de se «débrouiller». A aucun moment «cette Licence» ne vous demandera de vous enduire (vous ou votre œuvre) d'excréments humains (ni même animal). 43 | «Œuvre» est aussi appelée «travail» (quelques fois, l'extension «de sagouin» peut lui être apposée), «programme» ou tout autre terme relatif à ce qui a été effectué. Ainsi, une «documentation» ou un «manuel» peut être considéré comme une œuvre. 44 | «Auteur» signifie que la personne (ou groupe de personnes), qui utilise «cette Licence», se lave complètement les mains de la façon dont vous utiliserez son œuvre. 45 | 46 | Article 1. Permissions de base. 47 | 48 | Tous les droits accordés suivant «cette Licence» le sont jusqu’au terme de la volonté de son «Auteur». «Cette Licence» affirme explicitement votre permission illimitée de vous en sortir par vous même. «Cette Licence» reconnait vos propres droits d’usage raisonnable (droit de poser des questions à l'«Auteur», droit de discuter avec qui vous voulez de «cette Licence» et du contenu de l'œuvre). 49 | 50 | Vous pouvez critiquer, vitupérer et propager votre rancœur sans condition envers «cette Licence» ou l'œuvre courverte par celle-ci. 51 | 52 | L'«Auteur» peut à tout moment décider de passer outre «cette Licence» en accordant de l'aide (qui peut être elle-même couverte par «cette Licence») efficace ou non. Le fait d'apporter de l'aide n'enlève pas «cette Licence» à l'œuvre à laquelle elle est liée. 53 | Article 2. Limitation de responsabilité. 54 | 55 | L'«Auteur» peut-être considéré comme irresponsable et il incombe à l'utilisateur en priorité de se «démerder» par lui même. 56 | 57 | FIN DES TERMES ET CONDITIONS. 58 | Comment appliquer ces termes à vos nouvelles œuvres 59 | 60 | Si vous développez ou créez une nouvelle œuvre et voulez être le plus possible tranquille (histoire que le public vous lâche), la meilleure façon d’y parvenir est d’en faire une œuvre libre que chacun peut redistribuer et changer suivant ces termes-ci. 61 | 62 | Pour appliquer ces termes, attachez les notices suivantes à l'œuvre. Il est plus sûr de les attacher au début de chacun des fichiers sources afin de transporter de façon la plus effective possible l’exclusion de garantie ; et chaque fichier devrait comporter au moins la ligne de réservation de droit («copyright») et une indication permettant de savoir où la notice complète peut être trouvée : 63 | 64 | 65 | Copyright (C) — Tous droits réservés. 66 | 67 | Cette œuvre est distribuée SANS AUCUNE GARANTIE hormis celle d'être distribuée 68 | sous les termes de la Licence Demerdez-vous («Demerden Sie Sich License») 69 | telle que publiée par Flyounet : soit la version 1 de cette licence, 70 | soit (à votre gré) toute version ultérieure. 71 | 72 | Vous devriez avoir reçu une copie de la Licence Démerdez-vous avec cette 73 | œuvre ; si ce n’est pas le cas, consultez : 74 | . 75 | 76 | 77 | 78 | ############################################################################## 79 | -------------------------------------------------------------------------------- /scripts/bmflyounet_to_bm060.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | originalBM="${HOME}/bm.lnk" 5 | backBM="${HOME}/bm.lnk.before060" 6 | 7 | die() { echo "${@}"; exit 1; } 8 | 9 | [[ ! -f "${originalBM}" ]] && die "Please update this script to to tell where is your current bookmark. Aborting." 10 | [[ -f "${backBM}" ]] && die "A file already exist with this name ${backBM} (remove the file or edit the script). Aborintg." 11 | 12 | cp -f -- "${originalBM}" "${backBM}" || die "Unable to backup your bookmarks fie. Aborting." 13 | 14 | awk -F'|' 'BEGIN {OFS="|";} {$1=$1 "|" $NF; $NF=""; print $0;}' "${backBM}" | sed -e 's;|$;;' > "${originalBM}" 15 | 16 | echo "Export done for ${originalBM} (backup is ${backBM}). You should execute: bm -S" 17 | -------------------------------------------------------------------------------- /scripts/bmtj_to_bm060.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | originalBM="${HOME}/Dropbox/bookmarks" 5 | newBM="${HOME}/bm.lnk" 6 | 7 | die() { echo "${@}"; exit 1; } 8 | 9 | [[ ! -f "${originalBM}" ]] && die "Please update this script to to tell where is your old bookmark. Aborting." 10 | [[ -f "${newBM}" ]] && die "A file already exist with this name ${newBM} (remove the file or edit the script). Aborintg." 11 | 12 | [[ $(awk -F'|' '(NF > 3) { print $0;exit 2; }' "${originalBM}") -ne 0 ]] && die "Either your old file is not readable or some lines have more than 3 fields" 13 | 14 | A=0 15 | IFS='|' 16 | while read u T t; do 17 | m="$(md5sum <<< "${u}")" 18 | d="$(date "+%FT%TZ")" 19 | ((A++)) 20 | echo "${m%% *}|${d}|:${A}|${u}|${T}|${t//[ ]/,}" >> "${newBM}" 21 | done < "${originalBM}" 22 | 23 | echo "Export done from ${originalBM} to ${newBM}. You should execute: bm -S" 24 | --------------------------------------------------------------------------------