├── emojipick.png ├── LICENSE ├── .gitignore ├── emojiget.py ├── emojipick └── README.md /emojipick.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thingsiplay/emojipick/HEAD/emojipick.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Tuncay D. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .directory 2 | 3 | 4 | # Byte-compiled / optimized / DLL files 5 | __pycache__/ 6 | *.py[cod] 7 | *$py.class 8 | 9 | # C extensions 10 | *.so 11 | 12 | # Distribution / packaging 13 | .Python 14 | build/ 15 | develop-eggs/ 16 | dist/ 17 | downloads/ 18 | eggs/ 19 | .eggs/ 20 | lib/ 21 | lib64/ 22 | parts/ 23 | sdist/ 24 | var/ 25 | wheels/ 26 | share/python-wheels/ 27 | *.egg-info/ 28 | .installed.cfg 29 | *.egg 30 | MANIFEST 31 | 32 | # PyInstaller 33 | # Usually these files are written by a python script from a template 34 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 35 | *.manifest 36 | *.spec 37 | 38 | # Installer logs 39 | pip-log.txt 40 | pip-delete-this-directory.txt 41 | 42 | # Unit test / coverage reports 43 | htmlcov/ 44 | .tox/ 45 | .nox/ 46 | .coverage 47 | .coverage.* 48 | .cache 49 | nosetests.xml 50 | coverage.xml 51 | *.cover 52 | *.py,cover 53 | .hypothesis/ 54 | .pytest_cache/ 55 | cover/ 56 | 57 | # Translations 58 | *.mo 59 | *.pot 60 | 61 | # Django stuff: 62 | *.log 63 | local_settings.py 64 | db.sqlite3 65 | db.sqlite3-journal 66 | 67 | # Flask stuff: 68 | instance/ 69 | .webassets-cache 70 | 71 | # Scrapy stuff: 72 | .scrapy 73 | 74 | # Sphinx documentation 75 | docs/_build/ 76 | 77 | # PyBuilder 78 | .pybuilder/ 79 | target/ 80 | 81 | # Jupyter Notebook 82 | .ipynb_checkpoints 83 | 84 | # IPython 85 | profile_default/ 86 | ipython_config.py 87 | 88 | # pyenv 89 | # For a library or package, you might want to ignore these files since the code is 90 | # intended to run in multiple environments; otherwise, check them in: 91 | # .python-version 92 | 93 | # pipenv 94 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 95 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 96 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 97 | # install all needed dependencies. 98 | #Pipfile.lock 99 | 100 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 101 | __pypackages__/ 102 | 103 | # Celery stuff 104 | celerybeat-schedule 105 | celerybeat.pid 106 | 107 | # SageMath parsed files 108 | *.sage.py 109 | 110 | # Environments 111 | .env 112 | .venv 113 | env/ 114 | venv/ 115 | ENV/ 116 | env.bak/ 117 | venv.bak/ 118 | 119 | # Spyder project settings 120 | .spyderproject 121 | .spyproject 122 | 123 | # Rope project settings 124 | .ropeproject 125 | 126 | # mkdocs documentation 127 | /site 128 | 129 | # mypy 130 | .mypy_cache/ 131 | .dmypy.json 132 | dmypy.json 133 | 134 | # Pyre type checker 135 | .pyre/ 136 | 137 | # pytype static type analyzer 138 | .pytype/ 139 | 140 | # Cython debug symbols 141 | cython_debug/ 142 | -------------------------------------------------------------------------------- /emojiget.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | # Copyright (c) 2021 Tuncay D. 4 | # MIT License, see LICENSE 5 | 6 | import sys 7 | import pathlib 8 | import json 9 | import urllib.request 10 | import argparse 11 | 12 | parser = argparse.ArgumentParser() 13 | parser.add_argument('-f', '--filter', default='', 14 | help='print emoji only if name contains filter') 15 | parser.add_argument('-l', '--limit', default=0, type=int, 16 | help='limit the number of output emojis, defaults to 0 (no limit') 17 | parser.add_argument('-N', '--no-name', default=False, action='store_true', 18 | help='do not output emoji names') 19 | parser.add_argument('-w', '--wipe', default=False, action='store_true', 20 | help='delete temporary emoji files, redownload and recreate them') 21 | parser.add_argument('-c', '--lower-case', default=False, action='store_true', 22 | help='convert output to lower case only') 23 | parser.add_argument('-i', '--input', 24 | help='path to file with additional newline separated content') 25 | args = parser.parse_args() 26 | 27 | cdir = pathlib.Path('~/.cache/emojiget') 28 | cdir = cdir.expanduser() 29 | jfile = pathlib.Path(cdir / 'emoji.json') 30 | jfile_filtered = pathlib.Path(cdir / 'emoji_filtered.json') 31 | ifile = '' 32 | 33 | if args.wipe: 34 | jfile.unlink(missing_ok=True) 35 | jfile_filtered.unlink(missing_ok=True) 36 | cdir.rmdir() 37 | sys.exit(0) 38 | 39 | if args.input: 40 | ifile = pathlib.Path(args.input) 41 | ifile = ifile.expanduser() 42 | 43 | if jfile_filtered.exists(): 44 | jtext = jfile_filtered.read_text() 45 | emojis = json.loads(jtext) 46 | else: 47 | if jfile.exists(): 48 | jtext = jfile.read_text() 49 | else: 50 | cdir.mkdir(exist_ok=True) 51 | # Source: overatgithub/emoji.json 52 | # Alternate = 'https://gist.githubusercontent.com/thingsiplay/1f500459bc117cf0b63e1f5c11e03963/raw/d8e4b78cfe66862cf3809443c1dba017f37b61db/emojis.json' 53 | jurl = 'https://gist.githubusercontent.com/oliveratgithub/0bf11a9aff0d6da7b46f1490f86a71eb/raw/d8e4b78cfe66862cf3809443c1dba017f37b61db/emojis.json' 54 | jresponse = urllib.request.urlopen(jurl) 55 | jdata = jresponse.read() 56 | jtext = jdata.decode('utf-8') 57 | jfile.write_text(jtext) 58 | 59 | emojis = json.loads(jtext) 60 | 61 | # The alternate filter by "skin" compared to the "order" method will 62 | # include more stuff in the end, but makes it very slow and unusable in 63 | # dmenu. There is no problem in rofi, if you want switch. But remember 64 | # to wipe the cache with -w option. 65 | #emojis['emojis'] = [em for em in emojis['emojis'] if not 'skin' in em['name']] 66 | emojis['emojis'] = [em for em in emojis['emojis'] if em['order'] != ''] 67 | 68 | jfile_filtered.write_text(json.dumps(emojis)) 69 | 70 | if args.input and ifile.exists(): 71 | output = ifile.read_text() 72 | else: 73 | output = '' 74 | 75 | for index, emoji in enumerate(emojis['emojis']): 76 | if args.filter in emoji['name']: 77 | output += emoji['emoji'] 78 | if not args.no_name: 79 | output += ' ' + emoji['name'] + ' ~ ' + emoji['category'] 80 | if args.limit > 0 and index >= args.limit - 1: 81 | break 82 | output += '\n' 83 | if args.lower_case: 84 | output = output.lower() 85 | if output: 86 | print(output) 87 | -------------------------------------------------------------------------------- /emojipick: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Copyright (c) 2021,2022,2024 Tuncay D. 4 | # MIT License, see LICENSE 5 | 6 | # Note for Wayland users: 7 | # If use_rofi is not used (meaning set to 0), then script falls back to dmenu. 8 | # Unless the current session is run under Wayland instead X11, then it 9 | # fallsback to wofi. Be careful with running rofi or dmenu under Wayland, as 10 | # they key presses such as arrow keys to the terminal. Therefore I recommend 11 | # using wofi if you are in a Wayland session. 12 | 13 | # This variable points to the other script "emojiget.py", that is used to 14 | # retrieve and get a list of available emojis. If it is installed in the $PATH, 15 | # then its filename is enough. Otherwise use a path such as "./emojiget.py" or 16 | # any other fullpath. 17 | emojiget='emojiget.py' 18 | 19 | # Name-Size 20 | # font_family='Noto Color Emoji' 21 | font_family='Noto Sans' 22 | font_size='18' 23 | 24 | # Path to personal emojis file to display them at top of the dmenu list. 25 | favorites="${HOME}/.myemojis" 26 | 27 | # 1=Yes, 0=No 28 | use_rofi=0 29 | copy_to_clipboard=1 30 | show_notification=1 31 | print_emoji=1 32 | lower_case=1 33 | enable_favorites=1 34 | 35 | export SCRIPT_DIR='' 36 | SCRIPT_DIR="$(dirname "$(readlink -f "${0}")")" 37 | export PATH=.:${SCRIPT_DIR}:${PATH} 38 | 39 | if [[ "${use_rofi}" -eq 1 ]]; then 40 | if [ -n "${EMOJIPICK_CMD}" ]; then 41 | cmd_menu=("${EMOJIPICK_CMD}") 42 | else 43 | cmd_menu=( 44 | rofi 45 | -dmenu 46 | -l 47 | 15 48 | ) 49 | fi 50 | cmd_menu+=( 51 | -font 52 | "${font_family} ${font_size}" 53 | ) 54 | elif [[ "${XDG_SESSION_TYPE}" == "wayland" ]]; then 55 | if [ -n "${EMOJIPICK_CMD}" ]; then 56 | cmd_menu=("${EMOJIPICK_CMD}") 57 | else 58 | cmd_menu=( 59 | wofi 60 | --dmenu 61 | --lines 62 | 15 63 | ) 64 | fi 65 | # Note: wofi does not have an option for font selection. 66 | else 67 | if [ -n "${EMOJIPICK_CMD}" ]; then 68 | cmd_menu=("${EMOJIPICK_CMD}") 69 | else 70 | cmd_menu=( 71 | dmenu 72 | -l 73 | 15 74 | ) 75 | fi 76 | cmd_menu+=( 77 | -fn 78 | "${font_family}-${font_size}" 79 | ) 80 | fi 81 | 82 | if [[ "${XDG_SESSION_TYPE}" == "wayland" ]]; then 83 | cmd_clip=( 84 | wl-copy 85 | --trim-newline 86 | ) 87 | else 88 | cmd_clip=( 89 | xclip 90 | -rmlastnl 91 | -selection 92 | clipboard 93 | ) 94 | fi 95 | 96 | cmd_notify=( 97 | notify-send 98 | --urgency=low 99 | ) 100 | 101 | cmd_emojiget=("${emojiget}") 102 | 103 | if [[ "${lower_case}" -eq 1 ]]; then 104 | cmd_emojiget+=(--lower-case) 105 | fi 106 | 107 | if [[ "${enable_favorites}" -eq 1 ]]; then 108 | cmd_emojiget+=(--input) 109 | cmd_emojiget+=("${favorites}") 110 | fi 111 | 112 | # Run the menu and select an entry. 113 | selected_emoji_line=$( 114 | "${cmd_emojiget[@]}" | "${cmd_menu[@]}" 2>/dev/null | tr '\n' ' ' 115 | ) 116 | 117 | # Does it start with a double quote? 118 | if [[ ${selected_emoji_line} = \"* ]]; then 119 | # Select entire contents of quoted string 120 | emoji="$( 121 | awk -F '"' '{print $2}' <<<"${selected_emoji_line}" 122 | )" 123 | 124 | else 125 | # Select first field with awk default separator 126 | emoji="$( 127 | awk '{print $1}' <<<"${selected_emoji_line}" 128 | )" 129 | fi 130 | 131 | if [ -n "${emoji}" ]; then 132 | if [[ "${copy_to_clipboard}" -eq 1 ]]; then 133 | "${cmd_clip[@]}" <<<"${emoji}" 134 | fi 135 | 136 | if [[ "${show_notification}" -eq 1 ]]; then 137 | "${cmd_notify[@]}" "${emoji}" 138 | fi 139 | 140 | if [[ "${print_emoji}" -eq 1 ]]; then 141 | printf "%s\n" "${emoji}" 142 | fi 143 | fi 144 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Emoji Picker 2 | 3 | Get a selection of emojis and pick one to copy to clipboard. 4 | 5 | - **Author**: Tuncay D. 6 | - **License**: [MIT License](LICENSE) 7 | - **Source**: [Github source](https://github.com/thingsiplay/emojipick) 8 | 9 | ## Introduction 10 | 11 | Are you tired of the preinstalled Emoji tools that comes or does not come with 12 | your distro and you wish to use a different one? Yeah, me neither. Here is it 13 | anyway. 14 | 15 | ![dmenu](emojipick.png) 16 | 17 | ## Usage 18 | 19 | At first run a small file from Github will be downloaded, containing the emoji 20 | data. This is needed only once. The script itself will open a small bar on top 21 | of the screen, with a list of smileys and other emojis. Type in something to 22 | filter and narrow down the selection. Use the arrow keys to navigate and 23 | Enter to select. 24 | 25 | On selection a notification will appear and the emoji is copied to clipboard. 26 | It is also send to stdout (echo in terminal). There is not much to configure, 27 | just open the script itself and edit them as you like. If you want use `rofi` 28 | instead of `dmenu`, there is a setting to enable it in `emojipick` file. For 29 | that install rofi and enable it by changing the line `use_rofi=0` to 30 | `use_rofi=1` in the file "emojipick". If you are on Wayland, then the menu 31 | defaults to `wofi` instead `dmenu`. 32 | 33 | My recommendation is to assign a shortcut to the script `emojipick` and call it 34 | from any place you need. Alternatively you can also use it as a commandline 35 | tool, as it outputs to stdout. However I do not recommend running `dmenu` or 36 | `rofi` directly from terminal in a Wayland session, because they seem to send 37 | key presses (such as arrow keys) to the terminal while you are in the menu. So 38 | in Wayland I recommend installing `wofi` instead. 39 | 40 | You can use a favorites file with your emojis, which will be displayed at top 41 | of the dmenu list. The default location is at `~/.myemojis` and should be 42 | formatted like: 43 | 44 | ``` 45 | 💩 poop / imagination 46 | 👉😎👈 this guy 47 | "very@important.org" email 48 | "Some long text with spaces" sentence with spaces 49 | ``` 50 | 51 | It works with multiple emojis too. In fact, it even works with text until first 52 | space is encountered. If the first character is a quote `"`, then the entire 53 | content until closing quote is considered an emoji. This is useful if it 54 | contain spaces. The location of this file can be changed in the script 55 | `emojipick`. 56 | 57 | ## Customize command 58 | 59 | If the environmental variable `EMOJIPICK_CMD` is set, then it's value is used 60 | to run the menu instead rofi or dmenu. This can be a path or full command with 61 | options. Here some examples: 62 | 63 | $ EMOJIPICK_CMD='rofi -dmenu -l 5' ./emojipick 64 | 65 | $ EMOJIPICK_CMD='dmenu -fn' ./emojipick 66 | 67 | Using any alternative program must be compatible with the options of rofi or 68 | dmenu. 69 | 70 | ## How it works 71 | 72 | The entire script is based on 2 parts: one Python program responsible to 73 | download, convert and save the emoji database. The other script is a regular 74 | Bash script, calling the Python program and running menu and other commands. 75 | 76 | The emojis and their description are downloaded from 77 | [gist.github.com/oliveratgithub/emojis.json](https://gist.github.com/oliveratgithub/0bf11a9aff0d6da7b46f1490f86a71eb) . 78 | 79 | ## Installation and Requirements 80 | 81 | By default running `emojipick` will lookup and call `emojiget.py` as a command 82 | in the $PATH. But you can configure an alternative path in the script. The 83 | following programs are required depending the configuration and environment. 84 | 85 | Required: 86 | 87 | - `python3` 88 | - `awk` 89 | 90 | Under X11: 91 | 92 | - `dmenu` or `rofi` (depending on option `use_rofi`) 93 | - `xclip` (when option `copy_to_clipboard` is enabled) 94 | 95 | Under Wayland: 96 | 97 | - `wofi` (if option `use_rofi` is disabled, recommended) 98 | - `wl-copy` part of package `wl-clipboard` (when option `copy_to_clipboard` is 99 | enabled) 100 | 101 | Optional: 102 | 103 | - `notify-send` part of package `libnotify` (when option `show_notification` is 104 | enabled) 105 | 106 | Default font is set to "Noto Sans", but can be changed. The package name 107 | including this font varies depending on the distribution. 108 | 109 | - `noto-fonts` (on Arch) 110 | - `fonts-noto-core` (on Debian) 111 | 112 | ### Single command to install a setup in one go: 113 | 114 | - On Arch/X11 with rofi: 115 | 116 | ``` 117 | sudo pacman -Syu python3 awk rofi xclip libnotify noto-fonts 118 | ``` 119 | 120 | - On Arch/Wayland with wofi: 121 | 122 | ``` 123 | sudo pacman -Syu python3 awk wofi wl-clipboard libnotify noto-fonts 124 | ``` 125 | 126 | ## Additional files in use 127 | 128 | Additional to the scripts and required programs the following text files are 129 | in use: 130 | 131 | _created automatically_ 132 | 133 | - `~/.cache/emojiget/emoji.json` 134 | - `~/.cache/emojiget/emoji_filtered.json` 135 | 136 | _optional user created data_ 137 | 138 | - `~/.myemojis` 139 | 140 | These are the default paths, if not customized. 141 | 142 | ## See also 143 | 144 | - https://github.com/thingsiplay/emojicherrypick (an alternate) 145 | --------------------------------------------------------------------------------