From f56c95790824481c0593882162a52be6d754e112 Mon Sep 17 00:00:00 2001 From: Denis Kalyuzhnyy Date: Mon, 28 Dec 2020 18:38:37 +0300 Subject: [PATCH 1/6] [+] Heyteiler Beta --- .gitignore | 3 + Makefile | 14 +- README.md | 5 +- config.example | 74 ---- generate_types.sh | 9 + profiles/mp4-noaudio | 8 - profiles/mp4-pulse | 8 - profiles/webm-noaudio | 8 - pygmentize_types.txt | 399 +++++++++++++++++++++ targets/local | 24 ++ targets/s3 | 42 +++ targets/scp | 34 ++ teiler | 811 ++++++++++++++++++++++-------------------- teiler.conf | 44 +++ teiler_helper | 141 ++++---- uploader/s3 | 9 - uploader/scp | 9 - 17 files changed, 1061 insertions(+), 581 deletions(-) create mode 100644 .gitignore delete mode 100644 config.example create mode 100755 generate_types.sh delete mode 100644 profiles/mp4-noaudio delete mode 100644 profiles/mp4-pulse delete mode 100644 profiles/webm-noaudio create mode 100644 pygmentize_types.txt create mode 100644 targets/local create mode 100755 targets/s3 create mode 100644 targets/scp create mode 100644 teiler.conf delete mode 100755 uploader/s3 delete mode 100755 uploader/scp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a49ee69 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.teiler.history +.teiler.history.tmp +TODO diff --git a/Makefile b/Makefile index 40373ce..b9d6d1c 100644 --- a/Makefile +++ b/Makefile @@ -4,12 +4,10 @@ endif install: install -Dm755 teiler $(DESTDIR)$(PREFIX)/bin/teiler - install -Dm644 config.example $(DESTDIR)$(PREFIX)/share/doc/teiler/config.example install -Dm644 README.md $(DESTDIR)$(PREFIX)/share/doc/teiler/README.md - install -Dm644 config.example $(DESTDIR)/etc/teiler/teiler.conf - install -Dm755 teiler_helper $(DESTDIR)$(PREFIX)/bin/teiler_helper - install -Dm644 uploader/s3 $(DESTDIR)/etc/teiler/uploader/s3 - install -Dm644 uploader/scp $(DESTDIR)/etc/teiler/uploader/scp - install -Dm644 profiles/mp4-pulse $(DESTDIR)/etc/teiler/profiles/mp4-pulse - install -Dm644 profiles/mp4-noaudio $(DESTDIR)/etc/teiler/profiles/mp4-noaudio - install -Dm644 profiles/webm-noaudio $(DESTDIR)/etc/teiler/profiles/webm-noaudio + install -Dm644 teiler.conf $(DESTDIR)/etc/teiler/teiler.conf + install -Dm755 teiler_helper $(DESTDIR)/etc/teiler/teiler_helper + install -Dm644 pygmentize_types.txt $(DESTDIR)/etc/teiler/pygmentize_types.txt + install -Dm644 targets/local $(DESTDIR)/etc/teiler/targets/local + install -Dm644 targets/s3 $(DESTDIR)/etc/teiler/targets/s3 + install -Dm644 targets/scp $(DESTDIR)/etc/teiler/targets/scp diff --git a/README.md b/README.md index f44fadd..6914174 100644 --- a/README.md +++ b/README.md @@ -27,13 +27,12 @@ choose between screenshots or screencasts. * xclip * maim (https://github.com/naelstrof/maim) * slop (https://github.com/naelstrof/slop) -* copyq (https://github.com/hluk/CopyQ) +* tesseract (https://github.com/tesseract-ocr/tesseract) +* ImageMagic ## Optional Dependencies * imgurbash2 (https://github.com/ram-on/imgurbash2) -* filebin (http://git.server-speed.net/users/flo/filebin) * openssh (http://www.openssh.com) * ix (http://ix.io) * s3 cli tools -* tesseract (https://github.com/tesseract-ocr/tesseract) diff --git a/config.example b/config.example deleted file mode 100644 index d02e5ed..0000000 --- a/config.example +++ /dev/null @@ -1,74 +0,0 @@ -##### teiler configuration file ###### - -# rofi command. Make sure to have "$@" as last argument -_rofi () { - rofi -kb-accept-entry "!Return" "$@" -} - -# general variables - -# the path where images, videos and pastes should be saved -img_path=$HOME/Pictures/Screenshots -vid_path=$HOME/Videos/Screencasts -paste_path=$HOME/Pictures/Paste - -# set viewer for images and videos plus editor for images -viewer=eog -editor=pinta -player=mpv - -# Hitting Enter will upload -always_ul=1 - -# Uploading options -# Possible Choices for img_ul: fb, scp, s3, imgur -# Possible Choices for vid_ul: fb, scp, s3 -# Possible Choices for paste_ul: fb, scp, ix -img_ul=imgur -vid_ul=fb -paste_ul=ix - -# Screencast options -# Resolution to change to when recording in fullscreen -#res=800x600 - -# If you use a custom rate for X, set it here. -# rate=120 - -# Profile to use for screencasts -# profiles are stored in $HOME/.config/teiler/profiles -# teiler ships with 3 profiles atm. mp4-pulse, mp4-noaudio -# and webm-noaudio -# You can create your own profiles, but changes to existing profiles -# will be overwritten on startup -profile="mp4-pulse" - -# hotkeys -upload="Alt+1" -noupload="Alt+2" -delayup="Alt+3" -delaysave="Alt+4" - -view="Alt+1" -historyupload="Alt+2" -edit="Alt+3" -clip="Alt+4" - - -# Normally you don't want to change anything here! -SCREENCAST_PIDFILE=/tmp/$USER-teiler-screencast.pid -namekey=teiler -random_string=$(date +'%Y-%m-%d-%H%M%S') -img_filemask=img-$random_string.png -paste_filemask=txt-$random_string.txt - -# video filemask is without extension, since it gets the extension -# from set profile -vid_filemask=vid-$random_string - -help_color="#0C73C2" -hidecursor=yes -# slop options -slop_border=1 -slop_color="255,0,0" -hidecursor=yes diff --git a/generate_types.sh b/generate_types.sh new file mode 100755 index 0000000..b554aa2 --- /dev/null +++ b/generate_types.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +# Script for generate pygmentize_types.txt file +echo 'text .txt' > pygmentize_types.txt +pygmentize -L lexers | \ + tail -n +5 |\ + sed -n 'N;s/\n//p' |\ + sed -E -n 's/\* ([^,:]+).*filenames[^*]+\*(\.[^,)]+).*/\1 \2/p' |\ + grep -v 'text' >> pygmentize_types.txt diff --git a/profiles/mp4-noaudio b/profiles/mp4-noaudio deleted file mode 100644 index f8ab9e9..0000000 --- a/profiles/mp4-noaudio +++ /dev/null @@ -1,8 +0,0 @@ -# do not edit this file. instead make a copy under different name -# teiler will overwrite this file on start - -border="-show_region 1" -encopts="-r 30 -vcodec libx264 -pix_fmt yuv420p -s $res -movflags +faststart -acodec libmp3lame" -rect_encopts="-r 30 -c:v libx264 -preset slow -crf 18 -c:a libvorbis" -ext="mp4" -ffaudio="" diff --git a/profiles/mp4-pulse b/profiles/mp4-pulse deleted file mode 100644 index d2441e7..0000000 --- a/profiles/mp4-pulse +++ /dev/null @@ -1,8 +0,0 @@ -# do not edit this file. instead make a copy under different name -# teiler will overwrite this file on start - -border="-show_region 1" -encopts="-r 30 -vcodec libx264 -pix_fmt yuv420p -s $res -acodec libmp3lame" -rect_encopts="-r 30 -c:v libx264 -preset slow -crf 18 -c:a libvorbis" -ext="mp4" -ffaudio="-f alsa -ac 2 -i pulse" diff --git a/profiles/webm-noaudio b/profiles/webm-noaudio deleted file mode 100644 index 5aad1f0..0000000 --- a/profiles/webm-noaudio +++ /dev/null @@ -1,8 +0,0 @@ -# do not edit this file. instead make a copy under different name -# teiler will overwrite this file on start - -border="-show_region 1" -encopts="-c:v vp8 -threads 2 -pix_fmt yuv420p -crf 30 -b:v 0 -s $res" -rect_encopts="-r 30 -c:v vp8 -threads 4 -pix_fmt yuv420p -crf 30 -b:v 0" -ext="webm" -ffaudio="" diff --git a/pygmentize_types.txt b/pygmentize_types.txt new file mode 100644 index 0000000..cb1670f --- /dev/null +++ b/pygmentize_types.txt @@ -0,0 +1,399 @@ +text .txt +abap .abap +abnf .abnf +ada .adb +adl .adl +agda .agda +aheui .aheui +ahk .ahk +alloy .als +ampl .run +antlr-as .G +antlr-cpp .G +antlr-csharp .G +antlr-java .G +antlr-objc .G +antlr-perl .G +antlr-python .G +antlr-ruby .G +apl .apl +applescript .applescript +arduino .ino +arrow .arw +as .as +as3 .as +aspectj .aj +aspx-cs .aspx +aspx-vb .aspx +asy .asy +at .at +augeas .aug +autoit .au3 +awk .awk +bare .bare +bash .sh +bat .bat +bbcbasic .bbc +bc .bc +befunge .befunge +bib .bib +blitzbasic .bb +blitzmax .bmx +bnf .bnf +boa .boa +boo .boo +boogie .bpl +brainfuck .bf +bst .bst +bugs .bug +c-objdump .c-objdump +c .c +ca65 .s +cadl .cadl +camkes .camkes +capdl .cdl +capnp .capnp +cbmbas .bas +ceylon .ceylon +cfc .cfc +cfengine3 .cf +cfm .cfm +chai .chai +chapel .chpl +charmci .ci +cheetah .tmpl +cirru .cirru +clay .clay +clean .icl +clojure .clj +clojurescript .cljs +cmake .cmake +cobol .cob +cobolfree .cbl +coffee-script .coffee +common-lisp .cl +componentpascal .cp +console .sh-session +coq .v +cpp .cpp +cpp-objdump .cpp-objdump +cpsa .cpsa +cr .cr +crmsh .crmsh +croc .croc +cryptol .cry +csharp .cs +csound .orc +csound-document .csd +csound-score .sco +css+mozpreproc .css.in +css .css +cucumber .feature +cuda .cu +cypher .cyp +cython .pyx +d-objdump .d-objdump +d .d +dart .dart +dasm16 .dasm16 +delphi .pas +devicetree .dts +dg .dg +diff .diff +docker .docker +dpatch .dpatch +dtd .dtd +duel .duel +dylan-console .dylan-console +dylan-lid .lid +dylan .dylan +earl-grey .eg +easytrieve .ezt +ebnf .ebnf +ec .ec +ecl .ecl +eiffel .e +elixir .ex +elm .elm +emacs .el +email .eml +erl .erl-sh +erlang .erl +evoque .evoque +execline .exec +extempore .xtm +ezhil .n +factor .factor +fan .fan +fancy .fy +felix .flx +fennel .fnl +fish .fish +floscript .flo +forth .frt +fortran .f03 +fortranfixed .f +foxpro .PRG +freefem .edp +fsharp .fs +fstar .fst +gap .g +gas .s +gdscript .gd +genshi .kid +glsl .vert +gnuplot .plot +go .go +golo .golo +gooddata-cl .gdc +gosu .gs +groff .[1234567] +groovy .groovy +gst .gst +haml .haml +haskell .hs +haxeml .hxml +hlsl .hlsl +hsail .hsail +html+evoque .html +html+handlebars .handlebars +html+ng2 .ng2 +html+php .phtml +html+twig .twig +html .html +hx .hx +hybris .hy +hylang .hy +i6t .i6t +icon .icon +idl .pro +idris .idr +igor .ipf +inform6 .inf +inform7 .ni +ini .ini +io .io +ioke .ik +irc .weechatlog +isabelle .thy +j .ijs +jags .jag +jasmin .j +java .java +javascript+mozpreproc .js.in +jcl .jcl +js .js +jsgf .jsgf +json .json +jsonld .jsonld +jsp .jsp +julia .jl +juttle .juttle +kal .kal +kmsg .kmsg +koka .kk +kotlin .kt +lagda .lagda +lasso .lasso +lcry .lcry +lean .lean +less .less +lhs .lhs +lidr .lidr +limbo .b +liquid .liquid +live-script .ls +llvm-mir .mir +llvm .ll +logos .x +logtalk .lgt +lsl .lsl +lua .lua +make .mak +mako .mao +mako .mao +maql .maql +mask .mask +mason .m +mathematica .nb +matlab .m +md .md +modelica .mo +modula2 .def +monkey .monkey +monte .mt +moocode .moo +moon .moon +mosel .mos +mql .mq4 +ms .ms +mscgen .msc +mupad .mu +mxml .mxml +myghty .myt +nasm .asm +ncl .ncl +nemerle .n +nesc .nc +newlisp .lsp +newspeak .ns2 +nim .nim +nit .nit +nixos .nix +nsis .nsi +nusmv .smv +objdump-nasm .objdump-intel +objdump .objdump +objective-c++ .mm +objective-c .m +objective-j .j +ocaml .ml +octave .m +odin .odin +ooc .ooc +opa .opa +openedge .p +pan .pan +parasail .psi +pawn .p +peg .peg +perl .pl +perl6 .pl +php .php +pig .pig +pike .pike +pkgconfig .pc +pointless .ptls +pony .pony +postscript .ps +pot .pot +pov .pov +powershell .ps1 +praat .praat +prolog .ecl +promql .promql +properties .properties +protobuf .proto +pug .pug +puppet .pp +py2tb .py2tb +pypylog .pypylog +pytb .pytb +python .py +qbasic .BAS +qml .qml +qvto .qvto +racket .rkt +ragel-c .rl +ragel-cpp .rl +ragel-d .rl +ragel-em .rl +ragel-java .rl +ragel-objc .rl +ragel-ruby .rl +rb .rb +rconsole .Rout +rd .Rd +reason .re +rebol .r +red .red +redcode .cw +registry .reg +rexx .rexx +rhtml .rhtml +ride .ride +rnc .rnc +roboconf-graph .graph +roboconf-instances .instances +robotframework .robot +rql .rql +rsl .rsl +rst .rst +rts .rts +rust .rs +sarl .sarl +sas .SAS +sass .sass +sc .sc +scala .scala +scaml .scaml +scdoc .scd +scheme .scm +scilab .sci +scss .scss +sgf .sgf +shen .shen +shexc .shex +sieve .siv +silver .sil +singularity .def +slash .sla +slim .slim +slurm .sl +smali .smali +smalltalk .st +smarty .tpl +sml .sml +snobol .snobol +snowball .sbl +solidity .sol +sp .sp +sparql .rq +spec .spec +splus .S +sql .sql +sqlite3 .sqlite3-console +ssp .ssp +stan .stan +stata .do +swift .swift +swig .swg +systemverilog .sv +tads3 .t +tap .tap +tasm .asm +tcl .tcl +tcsh .tcsh +tea .tea +terraform .tf +tex .tex +thrift .thrift +tid .tid +tnt .tnt +todotxt .todotxt +toml .toml +treetop .treetop +ts .ts +tsql .sql +ttl .ttl +turtle .ttl +typoscript .typoscript +ucode .u +unicon .icn +urbiscript .u +usd .usd +vala .vala +vb.net .vb +vbscript .vbs +vcl .vcl +velocity .vm +verilog .v +vgl .rpf +vhdl .vhdl +vim .vim +wdiff .wdiff +webidl .webidl +whiley .whiley +x10 .x10 +xml+evoque .xml +xml .xml +xquery .xqy +xslt .xsl +xtend .xtend +xul+mozpreproc .xul.in +yaml+jinja .sls +yaml .yaml +yang .yang +zeek .zeek +zephir .zep +zig .zig diff --git a/targets/local b/targets/local new file mode 100644 index 0000000..5c137d6 --- /dev/null +++ b/targets/local @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +target_type=local + +## Destination settings +image_path="$HOME/Pictures/Screenshots/$(date +'%m.%Y')" +video_path="$HOME/Videos/Screencasts/$(date +'%m.%Y')" +text_path="$HOME/Documents/ClipboardSaves/$(date +'%m.%Y')" + +### Qaulity Screencast settings + +# It may be usefull to change qulity of screencast for diffrent targets +# If you don't care about video size just don't touch this settings :) + +# Only for filename, see video_filemask in ~/.config/teiler/config +ffmpeg_type="mp4" +# ffmpeg video capture settings for fullscreen mode (read more in ffmpeg docs) +ffmpeg_video_fullscreen="-f pulse -ac 2 -i default -r 30 -c:v libx264 -preset slow -crf 18 -c:a libvorbis " +# sometimes it is usefull to change settings for area mode +ffmpeg_video_area="${ffmpeg_video_fullscreen}" + +# You may change screen resolution for this target (it will changed back after +# stop recording) +#resolution=800x600 diff --git a/targets/s3 b/targets/s3 new file mode 100755 index 0000000..ec03494 --- /dev/null +++ b/targets/s3 @@ -0,0 +1,42 @@ +#!/bin/bash + +s3cmd_options="" +# s3 target parametrs +s3cmd_bucket=BUCKET +s3cmd_image_path="s3://${s3cmd_bucket}/Pictures/Screenshots/$(date +'%m.%Y')" +s3cmd_video_path="s3://${s3cmd_bucket}/Videos/Screencasts/$(date +'%m.%Y')" +s3cmd_text_path="s3://${s3cmd_bucket}/Documents/ClipboardSaves/$(date +'%m.%Y')" + +##### Advanced Block ##### + +# Sometimes files put on web-server over s3cmd, so your filepath +# may changed on some http resource. So, here you may set +# what to copy to clipboard when save_filepath=yes +# {filename} replaced by filename +s3cmd_image_filepath="${s3cmd_image_path}/{filename}" +s3cmd_video_filepath="${s3cmd_video_path}/{filename}" +s3cmd_text_filepath="${s3cmd_text_path}/{filename}" + +### Qaulity Screencast settings ### + +# It may be usefull to change qulity of screencast for diffrent targets +# If you don't care about video size just don't touch this settings :) + +# Only for filename, see video_filemask in ~/.config/teiler/config +ffmpeg_type="mp4" +# ffmpeg video capture settings for fullscreen mode (read more in ffmpeg docs) +ffmpeg_video_fullscreen="-f pulse -ac 2 -i default -r 30 -c:v libx264 -preset slow -crf 18 -c:a libvorbis " +# sometimes it is usefull to change settings for area mode +ffmpeg_video_area="${ffmpeg_video_fullscreen}" + +# You may change screen resolution for this target (it will changed back after +# stop recording) +#resolution=800x600 + +s3_bucket= +s3_path_img=path/to/images +s3_path_vid=path/to/videos +s3_path_paste=path/to/pastes +s3_http_img=http://S3_DOMAIN/path/to/images +s3_http_vid=http://S3_DOMAIN/path/to/videos +s3_http_paste=http://S3_DOMAIN/path/to/pastes diff --git a/targets/scp b/targets/scp new file mode 100644 index 0000000..19cebf9 --- /dev/null +++ b/targets/scp @@ -0,0 +1,34 @@ +#!/bin/bash + +scp_options="-P 22" +# scp target parametrs +scp_host=HOSTNAME +scp_image_path="${scp_host}:Pictures/Screenshots/$(date +'%m.%Y')" +scp_video_path="${scp_host}:Videos/Screencasts/$(date +'%m.%Y')" +scp_text_path="${scp_host}:Documents/ClipboardSaves/$(date +'%m.%Y')" + +##### Advanced Block ##### + +# Sometimes you may want to put files on web-server over scp, so your filepath +# may changed on http resource, so here you may set +# what to copy to clipboard when save_filepath=yes +# {filename} replaced by filename +scp_image_filepath="${scp_image_path}/{filename}" +scp_video_filepath="${scp_video_path}/{filename}" +scp_text_filepath="${scp_text_path}/{filename}" + +### Qaulity Screencast settings ### + +# It may be usefull to change qulity of screencast for diffrent targets +# If you don't care about video size just don't touch this settings :) + +# Only for filename, see video_filemask in ~/.config/teiler/config +ffmpeg_type="mp4" +# ffmpeg video capture settings for fullscreen mode (read more in ffmpeg docs) +ffmpeg_video_fullscreen="-f pulse -ac 2 -i default -r 30 -c:v libx264 -preset slow -crf 18 -c:a libvorbis " +# sometimes it is usefull to change settings for area mode +ffmpeg_video_area="${ffmpeg_video_fullscreen}" + +# You may change screen resolution for this target (it will changed back after +# stop recording) +#resolution=800x600 diff --git a/teiler b/teiler index bd881a6..d8690e8 100755 --- a/teiler +++ b/teiler @@ -1,491 +1,544 @@ #!/usr/bin/env bash -# set default rofi options -_rofi () { - rofi -kb-accept-entry "!Return" "$@" -} +# Source config files +if [[ -f "./teiler.conf" ]]; then + source_path='.' +elif [[ -f "$HOME/.config/teiler/teiler.conf" ]]; then + source_path="$HOME/teiler" +elif [[ -f "/etc/teiler/teiler.conf" ]]; then + source_path="/etc/teiler" +else + echo "ERROR: required teiler.conf not found" + exit +fi +if [[ -f "${source_path}/targets/local" ]]; then + source "${source_path}/targets/local" +else + echo "ERROR: required '${source_path}/targets/local' not found" + exit +fi +# Source config after local target +source "${source_path}/teiler.conf" + +# Check if video is recording now if [ -z "$XDG_RUNTIME_DIR" ]; then TMPDIR=$(mktemp -d) XDG_RUNTIME_DIR=$TMPDIR trap 'rm -rf $TMPDIR; exit' INT QUIT HUP TERM 0 fi -if [[ -d /etc/teiler ]] -then - source /etc/teiler/teiler.conf -fi +teiler_history_file="${source_path}/.teiler.history" -if [[ ! -d $HOME/.config/teiler ]]; then - mkdir $HOME/.config/teiler -fi +teiler_name_file="${XDG_RUNTIME_DIR}/__teiler_video_name" +teiler_pid_file="${XDG_RUNTIME_DIR}/__teiler_cast_pid" +teiler_resolution_file="${XDG_RUNTIME_DIR}/__teiler_resolution" +teiler_target_file="${XDG_RUNTIME_DIR}/__teiler_target" -if [[ ! -f $HOME/.config/teiler/config ]]; then - cp /etc/teiler/teiler.conf $HOME/.config/teiler/config + +video_recording="no" +if [[ -f "$teiler_pid_file" ]]; then + video_recording="yes" fi -export ext=${ext}; source $HOME/.config/teiler/config +# Add default rofi options +_rofi () { + rofi "${rofi_options}" "$@" +} -if [[ ! -d $HOME/.config/teiler/uploader ]]; then - mkdir $HOME/.config/teiler/uploader - if [[ -d /etc/teiler ]] - then - cp /etc/teiler/uploader/* $HOME/.config/teiler/uploader +check_path () { + # Autocreate $2 or ask in console + check_what="$1" + check_filepath="$2" + if [[ ! -d "$check_filepath" ]]; then + read -p "${check_what} path \"${check_filepath}\" does not exist. Create it? (Y/n)" -n 1 -r + if [[ $REPLY =~ ^[Yy]$ ]] || [[ $REPLY == "" ]]; then + mkdir -p "${check_filepath}" + elif [[ $REPLY =~ ^[Nn]$ ]]; then + exit + else + echo "Please enter y or n" + check_path + exit + fi fi -fi +} +fresh() { + ### Return all custom values to there default + delay=0 + image_target="${default_image_target}" + video_target="${default_video_target}" + text_target="${default_text_target}" + recognize_language="${default_recognize_language}" +} -if [[ ! -d $HOME/.config/teiler/profiles ]]; then - mkdir $HOME/.config/teiler/profiles -fi +showMenu () { + # Show teiler menu screen with help -if [[ -d /etc/teiler ]] -then - cd /etc/teiler/profiles - for i in *; do - if [[ ! -f $HOME/.config/teiler/profiles/"$i" ]]; then - cp /etc/teiler/profiles/"$i" $HOME/.config/teiler/profiles + _menu_name="$1" + shift + function_args=( "${@:1}" ) + + if [[ "${_menu_name}" == "teiler" ]]; then + _menu="< Exit\n---" else - cmp "$i" $HOME/.config/teiler/profiles/"$i" || cp -f /etc/teiler/profiles/"$i" $HOME/.config/teiler/profiles + _menu="< Return to Main Menu\n---" fi - done -fi -check_img_path () { - if [[ ! -d $img_path ]]; then - read -p "Image path \"${img_path}\" does not exist. Create it? (Y/n) " -n 1 -r - echo - if [[ $REPLY =~ ^[Yy]$ || $REPLY == "" ]]; then - mkdir -p "${img_path}" - elif [[ $REPLY =~ ^[Nn]$ ]]; then - exit + _menu_help_args='no' + for _menu_arg in "${function_args[@]}"; do + if [[ "$_menu_arg" == "-" ]]; then + _menu_help_args='yes' + _menu_opts=() + continue + fi + if [[ "$_menu_help_args" == "no" ]]; then + # Make menu dmenu string + let "_num=_num+1" + _menu="${_menu}\n${_num} ${_menu_arg}" + elif [[ "$_menu_help_args" == "yes" ]]; then + # Make help dmenu string + if [[ -z "$_menu_opt" ]]; then + _menu_opt="${_menu_arg}" + continue + fi + _menu_value="${_menu_arg}" + if [[ -z "$_menu_help" ]]; then + # If start help message then add span + _menu_help="${_menu_help}${_menu_opt}" + else + _menu_help="${_menu_help} | ${_menu_opt}" + fi + if [[ -n "$_menu_value" ]]; then + _menu_help="${_menu_help}: ${_menu_value}" + fi + _menu_opts+=( "${_menu_opt}" ) + _menu_opt="" + _menu_value="" + fi + done + _menu_help="${_menu_help}" + + if [[ ${_menu_help_args} == "yes" ]]; then + _menu_help_flag="-mesg" + _menu_help="$_menu_help" + else + _menu_help_flag="" + _menu_help="" + fi + _menu_result=$(echo -e "${_menu}" | _rofi "$_menu_help_flag" "$_menu_help" -dmenu -p "${_menu_name} >") + _menu_exit=$? + case "${_menu_exit}" in + 10) if [ -n "${_menu_opts[0]}" ]; then echo -n "${_menu_opts[0]}"; else echo -n "Return"; fi && exit ;; + 11) if [ -n "${_menu_opts[1]}" ]; then echo -n "${_menu_opts[1]}"; else echo -n "Return"; fi && exit ;; + 12) if [ -n "${_menu_opts[2]}" ]; then echo -n "${_menu_opts[2]}"; else echo -n "Return"; fi && exit ;; + 13) if [ -n "${_menu_opts[3]}" ]; then echo -n "${_menu_opts[3]}"; else echo -n "Return"; fi && exit ;; + esac + _num=$(echo -n "$_menu_result" | sed -nE 's/([0-9]+)\s.*/\1/p') + if [[ -n "${_num}" ]]; then + echo -n "${function_args[_num-1]}" else - echo "Please enter y or n" - check_img_path + echo -n "Return" fi - fi } -check_vid_path () { - if [[ ! -d $vid_path ]]; then - read -p "Video path \"${vid_path}\" does not exist. Create it? (Y/n) " -n 1 -r - echo - if [[ $REPLY =~ ^[Yy]$ || $REPLY == "" ]]; then - mkdir -p "${vid_path}" - elif [[ $REPLY =~ ^[Nn]$ ]]; then - exit - else - echo "Please enter y or n" - check_vid_path +mainMenu () { + fresh + + screencast_menu="[ Screencast ]>" + if [[ "$video_recording" == "yes" ]]; then + screencast_menu="[ Stop Recording Screencast ]" + fi + + menu=$( showMenu \ + "teiler" \ + "[ Screenshot ]>" \ + "$screencast_menu" \ + "[ SaveClipboard ]>" \ + "[ Recognition ]>" \ + "[ History ]>" + ) + + case "${menu}" in + "[ Screenshot ]>") screenshotMenu && exit;; + "[ Screencast ]>") screencastMenu && exit;; + "[ Stop Recording Screencast ]") screencastMenu && exit;; + "[ SaveClipboard ]>") clipboardMenu && exit;; + "[ Recognition ]>") recognitionMenu && exit;; + "[ History ]>") historyMenu && exit;; + "Return") exit;; + esac +} + +screenshotMenu () { + menu=$(showMenu Screenshot Area Fullscreen "Fullscreen All" - Target "${image_target}" Delay "${delay}") + case "${menu}" in + "Area") mode="area";; + "Fullscreen") mode="fullscreen";; + "Fullscreen All") mode="fullscreenAll";; + "Target") targetPrompt Image && screenshotMenu && exit;; + "Delay") delayPrompt && screenshotMenu && exit;; + "Return") mainMenu && exit;; + esac + + echo "${target_type}" + # Save image to clipboard and exit + if [[ "${target_type}" == "clipboard" ]]; then + maimCmd "${delay}" "-" "${mode}" | xclip -selection clipboard -t image/png + exit + fi + + maimCmd "${delay}" "${image_path}/${image_filename}" "${mode}" + saveInHistory Image "${image_path}/${image_filename}" + if [[ "$target_type" != "local" ]]; then + "${source_path}/teiler_helper" Image "${image_path}/${image_filename}" "${source_path}" "${image_target}" + elif [[ "$save_filepath" == "yes" ]]; then + echo "${img_output}" | xclip -selection clipboard fi - fi } -check_paste_path () { - if [[ ! -d $paste_path ]]; then - read -p "Paste path \"${paste_path}\" does not exist. Create it? (Y/n) " -n 1 -r - echo - if [[ $REPLY =~ ^[Yy]$ || $REPLY == "" ]]; then - mkdir -p "${paste_path}" - elif [[ $REPLY =~ ^[Nn]$ ]]; then - exit +targetPrompt () { + _prompt_type="${1}" + if [[ "$_prompt_type" == "Image" ]]; then + _posible_target_types="local|scp|s3|imgur|clipboard" + # Types allowed without any settings + _default_target_types="imgur|filebin|clipboard" + elif [[ "$_prompt_type" == "Video" ]]; then + _posible_target_types="local|scp|s3" + _default_target_types="" + elif [[ "$_prompt_type" == "Text" ]]; then + _posible_target_types="local|scp|ix.io" + _default_target_types="ix.io" else - echo "Please enter y or n" - check_paste_path + exit fi - fi -} -source "$HOME/.config/teiler/profiles/${profile}" + __sed_added=$(echo -n "${_default_target_types}" | sed "s/|/\\\\n/g") -vid_filemask="${vid_filemask}.${ext}" -save=$noupload + _targets=$(grep -l -R -E "target_type=(${_posible_target_types})" ./targets |\ + sed 's%./targets/%%' + ) -mainMenu () { - if [[ -f $XDG_RUNTIME_DIR/__teiler_cast_name ]] - then - filename="$(cat $XDG_RUNTIME_DIR/__teiler_cast_name)" - fi - - isRecording && STATE_RECORDING="2 Stop Recording Screencast" - - if [[ "$STATE_RECORDING" == "2 Stop Recording Screencast" ]] - then - HELP="${upload}: Upload | ${save}: No Upload" - menu=$(echo -e "< Exit\n---\n"$STATE_RECORDING"" | _rofi -dmenu -u 2 -p "teiler > ") - val=$? - if [[ $val -eq 1 ]] - then - exit - elif [[ $val -eq 0 ]] - then - askPrompt + # Ensure that default targets only added only one time + if [[ -n "${__sed_added}" ]]; then + _targets=$(echo "$_targets" |\ + grep -v -E "${_default_target_types}" |\ + sed -e "\$a${__sed_added}" + ) fi - elif [[ -z "$STATE_RECORDING" ]] - then - menu=$(echo -e "< Exit\n---\n1 [ Screenshots ]>\n2 [ Screencasts ]>\n3 [ Recognition ]>\n4 [ History ]>\n---\n5 Pastebin Text from Clipboard" | _rofi -dmenu -p "teiler > ") - val=$? - if [[ $val -eq 0 ]] - then - case "${menu}" in - "1 [ Screenshots ]>") screenshotMenu;; - "2 [ Screencasts ]>") askPrompt;; - "3 [ Recognition ]>") recognitionMenu;; - "4 [ History ]>") uploadMenu;; - "5 Pastebin Text from Clipboard") export filename="${paste_filemask}" && clipCmd && teiler_helper --upload text "${filename}";; - "< Exit") exit;; - esac - elif [[ $val -eq 1 ]] - then - exit + + result_target=$(echo -e "$_targets" | _rofi -dmenu -p "${_prompt_type} Target >") + # Source target + if [[ -f "${source_path}/targets/${result_target}" ]]; then + source "${source_path}/targets/${result_target}" + source "${source_path}/teiler.conf" + else + target_type="${result_target}" fi - fi -} -screenshotMenu () { - help_text=$(echo -e "Upload: ${upload} - Save: ${save} - Default: Enter" | column -s '-' -t) - line1=$(echo "${help_text}" | head -1) - HELP="${line1}" - export filename="${img_filemask}" - menu=$(echo -e "< Return to Main Menu\n---\n1 Monitor\n2 Fullscreen\n3 Area" | _rofi -dmenu -mesg "${HELP}" -p "Screenshot > ") - rofi_exit=$? - case "${menu}" in - "1 Monitor") mode="fullscreen"; desc="Monitor";; - "2 Fullscreen") mode="fullscreenAll"; desc="Monitor";; - "3 Area") mode="area"; desc="Area";; - "< Return to Main Menu") mainMenu;; - esac - if [[ $rofi_exit -eq 10 ]]; then - delayPrompt - if [[ $delay == "0" ]]; then maimCmd $mode "${filename}" && cd "${img_path}" && teiler_helper --upload image "${filename}" && exit - else notify-send -a "teiler" -t 1000 "teiler" "Taking Screenshot in "$delay" seconds"; maimCmd $mode "${filename}" && cd "${img_path}" && teiler_helper --upload image "${filename}" && exit - fi - elif [[ $rofi_exit -eq 11 ]]; then - delayPrompt - if [[ $delay == "0" ]]; then maimCmd $mode "${filename}" && exit - else notify-send -a "teiler" -t 1000 "teiler" "Taking Screenshot in "$delay" seconds"; maimCmd $mode "${filename}" - fi - elif [[ $rofi_exit -eq 1 ]]; then - exit - elif [[ $rofi_exit -eq 0 ]]; then - delayPrompt - if [[ $always_ul == "1" ]]; then - if [[ $delay == "0" ]]; then maimCmd $mode "${filename}" && cd "${img_path}" && teiler_helper --upload image "${filename}" && exit - else notify-send -a "teiler" -t 1000 "teiler" "Taking Screenshot in "$delay" seconds"; maimCmd $mode "${filename}" && cd "${img_path}" && teiler_helper --upload image "${filename}" && exit - fi - elif [[ $always_ul == "0" ]]; then - if [[ $delay == "0" ]]; then maimCmd $mode "${filename}" && exit - else notify-send -a "teiler" -t 1000 "teiler" "Taking Screenshot in "$delay" seconds"; maimCmd $mode "${filename}" && exit - fi - fi + if [[ "$_prompt_type" == "Image" ]]; then + image_target="${result_target}" + elif [[ "$_prompt_type" == "Video" ]]; then + video_target="${result_target}" + elif [[ "$_prompt_type" == "Text" ]];then + text_target="${result_target}" fi } +# Recognition recognitionMenu () { - mode="area"; desc="Area" - menu=$(echo -e "< Return to Main Menu\n---\n1 Colored on White\n2 Colored on Black" | _rofi -dmenu -p "Colors > ") + menu=$(showMenu Colors "Colored on White" "Colored on Dark" - Language "$recognize_language") case "${menu}" in - "1 Colored on White") colors="whiteback";; - "2 Colored on Black") colors="blackback";; - "< Return to Main Menu") mainMenu;; + "Colored on White") colors="whiteback";; + "Colored on Dark") colors="darkback";; + "Language") languagePrompt && recognitionMenu && exit;; + "Return") mainMenu && exit;; esac - delayPrompt - if [[ $delay != "0" ]]; then - notify-send -a "teiler" -t 1000 "teiler" "Recognize in "$delay" seconds"; - fi - maimCmd $mode - | tesseractCmd $colors; + maimCmd 0 - area | tesseractCmd $colors; +} + +languagePrompt () { + recognize_language=$(tesseract --list-langs | grep -v ' ' | _rofi -dmenu -p "Language >") } test_xrandr () { - if [[ -n $res ]]; then - output=$(xininfo -name); xrandr --output "$output" --mode "$res" --dryrun || { rofi -kb-move-word-forward '' -mesg "Resolution "${res}" not available"; exit 1; } + if [[ -n $resolution ]]; then + output=$(xininfo -name) + xrandr --output "$output" --mode "$resolution" --dryrun || { + echo "ERROR: Resolution "${resolution}" not available" + exit 1; + } fi } screencastMenu () { - filename="$(cat $XDG_RUNTIME_DIR/__teiler_cast_name)" - isRecording && STATE_RECORDING="2 Stop Recording Screencast" - if [[ "$STATE_RECORDING" == "2 Stop Recording Screencast" ]]; then - HELP="${upload}: Upload | ${save}: No Upload" - menu=$(echo -e "< Exit\n---\n"$STATE_RECORDING"" | _rofi -dmenu -u 2 -kb-custom-1 "${upload}" -kb-custom-2 "${save}" -mesg "${HELP}" -p "teiler > ") - val=$? - - if [[ "$menu" == "< Exit" ]]; then - exit - fi - if [[ $val -eq 10 ]]; then isRecording && stopRecording && sleep 2 && cd "${vid_path}" && teiler_helper --upload video "${filename}" && rm -f $XDG_RUNTIME_DIR/__teiler_cast_name; - elif [[ $val -eq 11 ]]; then isRecording && stopRecording; rm -f $XDG_RUNTIME_DIR/__teiler_cast_name; notify-send -a "teiler" -t 1000 "teiler" "Screencast saved"; exit - elif [[ $val -eq 1 ]]; then exit - elif [[ $val -eq 0 ]]; then - if [[ $always_ul ]]; then isRecording && stopRecording && sleep 2 && cd "${vid_path}" && teiler_helper --upload video "${filename}"; - elif [[ $always_ul == "0" ]]; then isRecording && stopRecording; rm -f $XDG_RUNTIME_DIR/__teiler_cast_name; notify-send -a "teiler" -t 1000 "teiler" "Screencast saved"; exit - fi + # Stop recording if it run + if [[ "$video_recording" == "yes" ]]; then + stopRecording + saveInHistory Video "${video_filepath}" + if [[ "$video_target" != "local" ]]; then + "${source_path}/teiler_helper" Video "$video_filepath" "${source_path}" "${video_target}" + elif [[ "$save_filepath" == "yes" ]]; then + echo "$video_filepath" | xclip -selection clipboard fi - - elif [[ -z "$STATE_RECORDING" ]]; then - menu=$(echo -e "< Return to Main Menu\n---\n1 Fullscreen\n2 Area" | _rofi -dmenu -p "Screencast > ") - val=$? - filename="${vid_filemask}" - echo "${filename}" > $XDG_RUNTIME_DIR/__teiler_cast_name - - if [[ $menu == "1 Fullscreen" ]]; then isRecording && stopRecording && sleep 2 || ffmpegCmd fullscreen; - elif [[ $menu == "2 Area" ]]; then isRecording && stopRecording && sleep 2 || ffmpegCmd area; - elif [[ $menu == "" ]]; then exit; - elif [[ $menu == "< Return to Main Menu" ]]; then mainMenu; fi + exit fi + + menu=$(showMenu Screencast Area Fullscreen - Target "$video_target") # TODO: choose audio inputs + case "${menu}" in + "Area") mode="area";; + "Fullscreen") mode="fullscreen";; + "Target") targetPrompt Video && screencastMenu && exit;; + "Return") mainMenu && exit;; + esac + echo "$video_target" > "$teiler_target_file" + ffmpegCmd "${video_path}/${video_filename}" $mode } -uploadMenu () { - menu=$(echo -e "< Return to Main Menu\n---\n1 Images\n2 Videos" | _rofi -dmenu -p "Uploads > ") - if [[ $menu == "1 Images" ]]; then imageMenu; - elif [[ $menu == "2 Videos" ]]; then videoMenu; - elif [[ $menu == "< Return to Main Menu" ]]; then mainMenu; - elif [[ $menu == "" ]]; then exit +clipboardMenu () { + if [[ -z "$(xclip -o -selection clipboard -t TARGETS | grep 'UTF8_STRING')" ]]; then + echo "Only UTF8_STRING supported" + exit fi -} -imageMenu () { - cd "${img_path}" - HELP="${view}: View | ${historyupload}: Upload | ${edit}: Edit | ${clip}: Copy to Clipboard" - imagemenu=$(echo -e "< Return to Upload Menu\n---\n$(ls -1 -r)" | _rofi -dmenu -select "${entry}" -kb-custom-1 "${view}" -kb-custom-2 "${historyupload}" -kb-custom-3 "${edit}" -kb-custom-4 "${clip}" -mesg "${HELP}" -p "Choose > ") - val=$? - - imagemenu2="${imagemenu%.*}" - if [[ "${imagemenu}" == "< Return to Upload Menu" ]]; then uploadMenu; fi - if [[ $val -eq 11 ]]; then teiler_helper --upload image $(echo -n "${imagemenu}"); export entry="${imagemenu}"; imageMenu - elif [[ $val -eq 10 || $val -eq 0 ]]; then $viewer "${imagemenu}"; export entry="${imagemenu}"; imageMenu - elif [[ $val -eq 12 ]]; then - cp "${imagemenu}" "${imagemenu2}-mod.png" - $editor "${imagemenu2}-mod.png" - export entry="${imagemenu}" - imageMenu - elif [[ $val -eq 13 ]]; then - copyq & - copyq write image/png - < "${imagemenu}"; copyq \select 0 - elif [[ $val -eq 1 ]]; then exit; + _texttypes=$(cat "${source_path}/pygmentize_types.txt" | awk '{print $1}' | sed ':a;N;$!ba;s/\n/ /g') + # _cliptext=$(xclip -o -selection clipboard) + menu=$(showMenu "Text Format" $_texttypes - Target "$text_target") + case "${menu}" in + Target) targetPrompt Text && clipboardMenu && exit;; + Return) mainMenu && exit;; + *) _filetype="${menu}";; + esac + _file_extention=$(cat "${source_path}/pygmentize_types.txt" | grep "^${_filetype}\s\+" | awk '{print $2}') + # Replace extention + _text_output=$(echo "${text_path}/${text_filename}" |\ + sed -E "s/(.*)\.[^.]+/\1${_file_extention}/" + ) + clipboardCmd "${_text_output}" + saveInHistory Text "${_text_output}" + if [[ "$target_type" != "local" ]]; then + "${source_path}/teiler_helper" Text "${_text_output}" "${source_path}" "${text_target}" + # TODO + elif [[ "$save_filepath" == "yes" ]]; then + echo "${_text_output}" | xclip -selection clipboard fi } -videoMenu () { - cd "${vid_path}" - HELP="${view}: View | ${historyupload}: Upload" - videomenu=$(echo -e "< Return to Upload Menu\n---\n$(ls -1)" | _rofi -dmenu -select "${entry}" -kb-custom-1 "${view}" -kb-custom-2 "${historyupload}" -mesg "${HELP}" -p "Choose > ") - val=$? - videomenu2="${videomenu%.*}" - if [[ "${videomenu}" == "< Return to Upload Menu" ]]; then uploadMenu; fi - if [[ $val -eq 11 ]]; then teiler_helper --upload video "${videomenu}"; - elif [[ $val -eq 10 || $val -eq 0 ]]; then $player "${videomenu}"; export entry="${videomenu}"; videoMenu - elif [[ $val -eq 1 ]]; then exit - fi +clipboardCmd () { + check_path SaveClipboard "$(dirname "$1")" + xclip -o -selection clipboard >> "$1" } -isRecording () { [[ -f "$SCREENCAST_PIDFILE" ]] || return 1; } +historyMenu () { + menu=$(showMenu History Image Video Text) + case "${menu}" in + Image|Video|Text) typeHistoryMenu "${menu}" && exit;; + Return) mainMenu && exit;; + esac +} -stopRecording () { - local pid - if [[ -a $XDG_RUNTIME_DIR/teiler_res ]]; then - res=$(cat $XDG_RUNTIME_DIR/teiler_res) +typeHistoryMenu () { + _history_type="${1}" + if [[ "$_history_type" == "Image" ]]; then + history_target="${image_target}" + elif [[ "$_history_type" == "Video" ]]; then + history_target="${video_target}" + elif [[ "$_history_type" == "Text" ]]; then + history_target="${text_target}" fi - [[ -f $SCREENCAST_PIDFILE ]] && { pid=$(cat "$SCREENCAST_PIDFILE"); isRecording && kill "$pid"; rm "$SCREENCAST_PIDFILE"; } - notify-send -a "teiler" -t 1000 "teiler" "Stopped recording" - if [[ -z $rate ]]; then - output=$(xininfo -name); xrandr --output "$output" --mode "$res"; rm -f $XDG_RUNTIME_DIR/teiler_res; return 0 + + _history_items=$( grep "${_history_type}" "${teiler_history_file}" | sed "s/${_history_type}\s\+//" | sed ':a;N;$!ba;s/\n/ /g') + menu=$(showMenu "History ${_history_type}" ${_history_items} - Target ${history_target}) + case "${menu}" in + Target) targetPrompt "${_history_type}" && typeHistoryMenu "${_history_type}" && exit;; + Return) mainMenu && exit;; + *) echo "";; + esac + + if [[ "$target_type" == "local" ]]; then + xdg-open "${menu}" + # Only images has target: clipboard in teiler + elif [[ "$target_type" == "clipboard" ]]; then + cat "${menu}" | xclip -selection clipboard -t image/png else - if [[ -n $res ]]; then - output=$(xininfo -name); xrandr --output "$output" --mode "$res" --rate "${rate}"; rm -f $XDG_RUNTIME_DIR/teiler_res; return 0 - fi + "${source_path}/teiler_helper" "${_history_type}" "${menu}" "${source_path}" "${history_target}" fi } -slopCmd () { - slopString=$(slop -b "$slop_border" -c "$slop_color") - if [[ "$slopString" == *"Cancel=true"* ]]; then - exit +saveInHistory () { + _history_type="${1}" + _item_path="${2}" + _history_tmp_file="${teiler_history_file}.tmp" + echo "${_history_type} ${_item_path}" > "${_history_tmp_file}" + if [[ -f "${teiler_history_file}" ]]; then + head -199 "${teiler_history_file}" >> "${_history_tmp_file}" fi - } + mv "${_history_tmp_file}" "${teiler_history_file}" +} + +stopRecording () { + # TODO + echo "im here" + video_filepath="$(cat "${teiler_name_file}")" + video_pid="$(cat "${teiler_pid_file}")" + video_old_resolution="$(cat "${teiler_resolution_file}")" + video_target="$(cat "${teiler_target_file}")" + if [[ -z "$video_filepath" ]] ||\ + [[ -z "$video_old_resolution" ]] ||\ + [[ -z "$video_target" ]]; then + _witherrors=" with errors" + rm -f "$teiler_name_file" + rm -f "$teiler_resolution_file" + rm -f "$teiler_target_file" + fi + if [[ -f "${teiler_pid_file}" ]]; then + echo "tested pid: $(ps -p $video_pid)" >> ~/teiler.log + if [[ -n "$(pgrep ffmpeg | grep "$video_pid")" ]]; then + kill "$video_pid" + else + _witherrors=" with errors" + fi + rm -f "${teiler_pid_file}" + fi + + notify-send -a "teiler" -t 1000 "teiler" "Stopped recording${_witherrors}" + output=$(xininfo -name); + xrandr --output "$output" --mode "$video_old_resolution"; + rm -f "${teiler_resolution_file}"; + +} ffmpegCmd () { round() { echo $(( ${1:?need one argument} / 2 * 2)) } - - xres=$(echo "$res" | awk -F 'x' '{ print $1 }') - yres=$(echo "$res" | awk -F 'x' '{ print $2 }') - - if [[ -n $res ]]; then - res_now="$(xininfo -mon-size | sed 's/ /x/')" - else - res="$(xininfo -mon-size | sed 's/ /x/')" - fi - - source "$HOME/.config/teiler/profiles/${profile}" - - echo "${filename}" > $XDG_RUNTIME_DIR/__teiler_cast_name - if [[ $1 == "fullscreen" ]]; then - isRecording && { notify "$time" 'Screencast already in progress'; echo "Already recording Screen"; exit 1; } - ffmpeg_display=$(echo $DISPLAY) - ffmpeg_offset="$(xininfo -mon-x),$(xininfo -mon-y)" - if [[ -n $res_now ]]; then - echo "$res_now" > $XDG_RUNTIME_DIR/teiler_res - fi - if [[ $res_now == $res ]]; then echo " " - else output=$(xininfo -name); xrandr --output "$output" --mode "$res"; sleep 5; fi - [[ -f "${vid_path}/${filename}" ]] && rm "${vid_path}/${filename}" - if [[ -z $ffaudio ]]; then ffmpeg -f x11grab ${border} -s $res -i $ffmpeg_display+$ffmpeg_offset $encopts "${vid_path}/${filename}" & - else ffmpeg -f x11grab ${border} -s $res -i $ffmpeg_display+$ffmpeg_offset $ffaudio $encopts "${vid_path}/${filename}" & - fi - echo "$!" > "$SCREENCAST_PIDFILE" + + video_output="${1}" + check_path "Video" "$(dirname ${video_output})"; + [[ -f "${video_output}" ]] && rm "${video_output}" # rewrite file if exist + + # Prepare resolution + resolution_now="$(xininfo -mon-size | sed 's/ /x/')" + echo "$resolution_now" > "${teiler_resolution_file}" + if [[ -z "$resolution" ]]; then + resolution="$resolution_now" + fi + + if [[ "$resolution_now" != "$resolution" ]]; then + # Change resolution before start video + test_xrandr + output=$(xininfo -name) + xrandr --output "$output" --mode "$resolution" + sleep 5; + fi + + echo "${video_output}" > "${teiler_name_file}" # Safe video name for next time + if [[ "$2" == "fullscreen" ]]; then + ffmpeg_display_opts="-s $resolution -i $(echo $DISPLAY)+$(xininfo -mon-x),$(xininfo -mon-y)" + ffmpeg -f x11grab $ffmpeg_display_opts \ + ${ffmpeg_video_fullscreen} "${video_output}" & + echo "$!" > "${teiler_pid_file}" notify-send -a "teiler" -t 1000 "teiler" "Screencast started" - elif [[ $1 == "area" ]]; then - read -r X Y W H G ID < <(slop -f "%x %y %w %h %g %i") + elif [[ $2 == "area" ]]; then + read -r X Y W H G ID < <(slop ${slop_options} -f "%x %y %w %h %g %i") X=$(round $X) Y=$(round $Y) W=$(round $W) H=$(round $H) - isRecording && { notify "$time" 'Screencast already in progress'; echo "Already recording Screen"; exit 1; } - ffmpeg_display=$(echo $DISPLAY); ffmpeg_offset=$(echo $(xininfo -mon-x),$(xininfo -mon-y)) - [[ -f "${vid_path}/${filename}" ]] && rm "${vid_path}/${filename}" - if [[ -z $ffaudio ]]; then ffmpeg -f x11grab ${border} -s "$W"x"$H" -i $ffmpeg_display+$X,$Y $rect_encopts "${vid_path}/${filename}" & - else ffmpeg -f x11grab ${border} -s "$W"x"$H" -i $ffmpeg_display+$X,$Y $ffaudio $rect_encopts "${vid_path}/${filename}" & - fi - echo "$!" > "$SCREENCAST_PIDFILE" + echo "size: $X $Y $W $H" >> ~/t1iler.log # debug + ffmpeg_display_opts="-s "$W"x"$H" -i $(echo $DISPLAY)+$X,$Y)" + ffmpeg -show_region 1 -f x11grab $ffmpeg_display_opts \ + ${ffmpeg_video_area} "${video_output}" & + echo "$!" > "${teiler_pid_file}" notify-send -a "teiler" -t 1000 "teiler" "Screencast started" + # TODO: Run slop again? fi } tesseractCmd () { - if [[ $1 == "whiteback" ]]; then - tesseract - - -c page_separator="" | xclip -selection clipboard - elif [[ $1 == "blackback" ]]; then + if [[ "$1" == "whiteback" ]]; then + tesseract -l "$recognize_language" - - -c page_separator="" | xclip -selection clipboard + elif [[ "$1" == "darkback" ]]; then # tesseract always wait colored on white images - convert - -set colorspace Gray -separate -average -negate - | tesseract - - -c page_separator="" | xclip -selection clipboard + convert - -set colorspace Gray -separate -average -negate - | tesseract -l "$recognize_language" - - -c page_separator="" | xclip -selection clipboard fi + notify-send -a "teiler" -t 1000 "teiler" "Recognition done!" } maimCmd () { - if [[ $hidecursor == "yes" ]]; then - cursor="--hidecursor" - elif [[ $hidecursor == "no" ]]; then - cursor="" - fi - if [[ $slop_color == "" ]]; then - rect_color="" - else - rect_color="-c ${slop_color}" - fi - if [[ $slop_border == "" ]]; then - rect_border="" - else - rect_border="-b ${slop_border}" - fi + # maimCmd delay path mode + #Examples: + # maimCmd 0 "/tmp/myimage.png" fullscreen + # maimCmd 5 "-" area - if [[ ! -z $delay && "$delay" != "0" ]]; then - maim_delay="-d ${delay}" - else + + # Check settings + maim_cursor="--hidecursor" + + # Check args + if [[ "${1}" == "0" ]]; then maim_delay="" + else + maim_delay="-d ${1}" fi if [[ ${2} == "-" ]]; then img_output="/dev/stdout" else - img_output="${img_path}/${2}" + img_output="${2}" + check_path "Image" "$(dirname ${img_output})"; fi - if [[ $1 == "area" ]]; then maim ${maim_delay} $cursor ${rect_border} ${rect_color} -s ${img_output}; - elif [[ $1 == "active" ]]; then maim ${maim_delay} -i $(xdotool getactivewindow) ${img_output}; - elif [[ $1 == "fullscreen" ]]; then maim ${maim_delay} $cursor -g $(xininfo -mon-width)x$(xininf3 -mon-height)+$(xininfo -mon-x)+$(xininfo -mon-y) ${img_output}; - elif [[ $1 == "fullscreenAll" ]]; then maim ${maim_delay} $cursor ${img_output}; + if [[ $3 == "area" ]]; then + maim_mode_options="-s ${slop_options}" + elif [[ $3 == "active" ]]; then + maim_mode_options="-i $(xdotool getactivewindow)" + elif [[ $3 == "fullscreen" ]]; then + maim_mode_options="-g $(xininfo -mon-width)x$(xininfo -mon-height)+$(xininfo -mon-x)+$(xininfo -mon-y)" + elif [[ $3 == "fullscreenAll" ]]; then + maim_mode_options="" fi - if [[ ! -z "${delay}" && "${delay}" != "0" ]]; then - notify-send -a "teiler" -t 1000 "teiler" "Chick!"; - fi -} + [[ -f "${img_output}" ]] && rm "${img_output}" # rewrite file if exist + maim ${maim_mode_options} ${maim_delay} ${maim_cursor} ${img_output} -askPrompt () { - filename="$(cat $XDG_RUNTIME_DIR/__teiler_cast_name)" - isRecording && STATE_RECORDING="Recording" - if [[ -z "$STATE_RECORDING" ]]; then - filename="${vid_filemask}" - echo "${filename}" > $XDG_RUNTIME_DIR/__teiler_cast_name - menu=$(echo -e "< Exit\n---\n1 Fullscreen\n2 Area" | _rofi -dmenu -p "> ") - if [[ $menu == "1 Fullscreen" ]]; then isRecording && stopRecording && sleep 2 || ffmpegCmd fullscreen; - elif [[ $menu == "2 Area" ]]; then isRecording && stopRecording && sleep 2 || ffmpegCmd area; - elif [[ $menu == "" ]]; then exit - fi - else - filename="$(cat $XDG_RUNTIME_DIR/__teiler_cast_name)" - isRecording && stopRecording && sleep 2 - ask=$(echo -e "1 Yes\n2 No" | _rofi -dmenu -p "Upload? > ") - if [[ $ask == "1 Yes" ]]; then cd "${vid_path}" && teiler_helper --upload video "${filename}" && rm -f $XDG_RUNTIME_DIR/__teiler_cast_name; - elif [[ $ask == "2 No" ]]; then rm -f $XDG_RUNTIME_DIR/__teiler_cast_name; - fi + if [[ "${1}" != "0" ]]; then + notify-send -a "teiler" -t 1000 "teiler" "Chick!"; fi } -clipCmd () { - (xclip -o) > "${paste_path}/${paste_filemask}" -} - delayPrompt () { delay=$(echo -e "$(seq 0 10)" | _rofi -dmenu -p "Choose Delay > ") - if [[ $delay == "" ]]; then + if [[ -z "$delay" ]]; then exit fi } -helpCmd () { - cat << EOF +echo_help () { +cat << EOF teiler - a rofi-driven screen{shot,cast} utility -(C) Rasmus Steinke ---screenshot open screenshots menu ---screencast open screencasts menu ---history {images,video} open history menus ---paste upload text from clipboard ---togglecast start/stop screencast ---quick image {area,fullscreen,all,active} quickly create screenshot and upload ---quick video {area,fullscreen} quickly create screenshot and optionally upload ---quickcopy {area,fullscreen,all} quickly create screenshot and copy + +screenshot [quick] [target] [delay] + open screenshots menu/make quick screenshot to target +screencast [quick] [target] [delay] + open screencasts menu/quick screencast start or stop +saveclipboard [quick] [target] [delay] + open clipboard menu/quick save clipboard to target +recognition [quick] [delay] + open recognition menu/quick recognize text to clipboard +history [quick] [type] [target] + open history menu/quick send last item to target EOF } - - -if [[ $1 == "--screenshot" ]]; then check_img_path; screenshotMenu -elif [[ $1 == "--screencast" ]]; then check_vid_path; screencastMenu -elif [[ $1 == "--paste" ]]; then check_paste_path; export filename="${paste_filemask}" && clipCmd && teiler_helper --upload text "${filename}" -elif [[ $1 == "--togglecast" ]]; then check_vid_path; askPrompt -elif [[ $1 == "--history" ]]; then - if [[ $2 == "images" ]]; then check_img_path; imageMenu - elif [[ $2 == "videos" ]]; then check_vid_path; videoMenu - fi -elif [[ $1 == "--quick" ]]; then - if [[ $2 == "image" ]]; then - check_img_path - filename="${img_filemask}" - if [[ $3 == "area" ]]; then maimCmd area "${filename}" && cd "${img_path}" && teiler_helper --upload image "${filename}" - elif [[ $3 == "active" ]]; then maimCmd active "${filename}" && cd "${img_path}" && teiler_helper --upload image "${filename}" - elif [[ $3 == "fullscreen" ]]; then maimCmd fullscreen "${filename}" && cd "${img_path}" && teiler_helper --upload image "${filename}" - elif [[ $3 == "all" ]]; then maimCmd fullscreenAll "${filename}" && cd "${img_path}" && teiler_helper --upload image "${filename}" - fi - elif [[ $2 == "video" ]]; then - check_vid_path - filename="${vid_filemask}" - if [[ $3 == "area" ]]; then isRecording && askPrompt && sleep 2 || ffmpegCmd area; - elif [[ $3 == "fullscreen" ]]; then isRecording && askPrompt && sleep 2 || ffmpegCmd fullscreen; - fi - else echo "possible options for \"--quick\": image, video" - fi - -elif [[ $1 == "--quickcopy" ]]; then - check_img_path; - filename="${img_filemask}" - if [[ $2 == "area" ]]; then copyq & maimCmd area "${filename}" && cd "${img_path}" && copyq write image/png - < "${filename}"; copyq select 0 - elif [[ $2 == "fullscreen" ]]; then copyq & maimCmd fullscreen "${filename}" && cd "${img_path}" && copyq write image/png - < "${filename}"; copyq select 0 - elif [[ $2 == "all" ]]; then copyq & maimCmd fullscreenAll "${filename}" && cd "${img_path}" && copyq write image/png - < "${filename}"; copyq select 0 - fi -elif [[ $1 == "--help" || $1 == "-h" ]]; then - helpCmd -else - check_img_path; check_vid_path; mainMenu -fi +case $key in + quick) cmd_quick="--quick" ; shift;; + screenshot) shift; screenshotMenu "${cmd_quick}" "$@" && exit;; + screencast) shift; screencastMenu "${cmd_quick}" "$@" && exit;; # TODO + saveclipboard) shift; clipboardMenu "${cmd_quick}" "$@" && exit;; # TODO + recognition) shift; recognitionMenu "${cmd_quick}" "$@" && exit;; # TODO + history) shift; historyMenu "${cmd_quick}" "$@" && exit;; # TODO + -h|--help) echo_help && exit;; + *) mainMenu && exit;; +esac diff --git a/teiler.conf b/teiler.conf new file mode 100644 index 0000000..97941f1 --- /dev/null +++ b/teiler.conf @@ -0,0 +1,44 @@ +##### teiler configuration file ###### + +### Screenshots Settings ### +# This destination used as default (One from: ./targets) +# Possible target_type var: local, clipboard, filebin, scp, s3, imgur +default_image_target=local +# Filemask for created image files. +image_filename="image-$(date +'%Y-%m-%d-%H%M%S').png" + + +### Screencasts Settings ### +# This destination used as default (one from ./targets) +# Possible target_type var: local, filebin, scp, s3 +default_video_target=local +# Filemask for created video files. See ~/.config/teiler/targets for ${ffmpeg_type} value +video_filename="video-$(date +'%Y-%m-%d-%H%M%S').${ffmpeg_type}" +# Pidfile +video_pidfile=/tmp/$USER-teiler-screencast.pid + +### Save Clipboard Settings ### +# This destination used as default (use one from ~/.config/teiler/destination) +# Possible Choices for paste: fb, scp, ix.io +default_text_target=local +# Filemask for created text files. See ~/.config/teiler/targets for ${ffmpeg_type} value +text_filename="text-$(date +'%Y-%m-%d-%H%M%S').txt" + +### Recognition Settings ### +# tesseract defautl language, from 4.0.0 version is possible to use several +# languages but i'm not recommend it +default_recognize_language="eng" + +### History Settings ### + +### Advanced variables ### +# Save filepath in clipboard +save_filepath=yes +# The color of help messages in rofi headers +help_color="#0C73C2" +# Slop options +slop_options="-b 2 -c 255,0,0" +# TODO: test -r crosshair + +# Add some custom rofi options +#rofi_options='-kb-accept-entry "!Return"' diff --git a/teiler_helper b/teiler_helper index fe94f63..8861fd4 100755 --- a/teiler_helper +++ b/teiler_helper @@ -1,90 +1,81 @@ #!/usr/bin/env bash -source $HOME/.config/teiler/config -if [[ "$img_ul" == "s3" || "$img_ul" == "scp" ]]; then - source $HOME/.config/teiler/uploader/$img_ul -fi -if [[ "$vid_ul" == "s3" || "$vid_ul" == "scp" ]]; then - source $HOME/.config/teiler/uploader/$vid_ul -fi -if [[ "$paste_ul" == "s3" || "$paste_ul" == "scp" ]]; then - source $HOME/.config/teiler/uploader/$paste_ul -fi - -# define uploaders -# images -if [[ $img_ul == "fb" ]]; then - imageUpload () { - if [[ $(echo "$files" | wc -w) -gt 1 ]]; then - cd "${img_path}"; fb -m ${@}; x_clip; notify-send -a "teiler" "Image Uploaded" "$(xclip -o)" - else - cd "${img_path}"; fb ${@}; x_clip; notify-send -a "teiler" "Image Uploaded" "$(xclip -o)"; - fi - } +# Example +# teiler_helper image "${image_path}/${image_filename}" "${source_path}" "${image_target}" +echo "vars: $@" # debug -elif [[ $img_ul == "scp" ]]; then - imageUpload () { for x in $files; do scpUpload "Image" "${img_path}" "$x" "${scp_host}" "${scp_path_img}" "${http_img}"; done; } -elif [[ $img_ul == "imgur" ]]; then - imageUpload () { cd "${img_path}"; for x in $files; do imgurbash2 "${x}"; x_clip; notify-send -a "teiler" "Image Uploaded" "$(xclip -o)"; done; } -elif [[ $img_ul == "s3" ]]; then - imageUpload () { cd "${img_path}"; s3cmd --no-progress put "${1}" "s3://${s3_bucket}/${s3_path_img}/"; notify-send -a "teiler" "Image Uploaded" "${s3_http_img}/${1}"; echo -n "${s3_http_img}/${1}" | xclip; x_clip; } -else - imageUpload () { echo "No image uploader set. check example config"; } -fi +item_type="${1}" +item_path="${2}" +source_path="${3}" +item_target="${4}" +item_basename="$(basename ${item_path})" -# Videos -if [[ $vid_ul == "fb" ]]; then - videoUpload () { cd "${vid_path}"; fb "${1}"; x_clip; notify-send -a "teiler" "Video Uploaded" "$(xclip -o)"; } -elif [[ $vid_ul == "scp" ]]; then - videoUpload () { scpUpload "Video" "${vid_path}" "$1" "${scp_host}" "${scp_path_vid}" "${http_vid}"; } -elif [[ $vid_ul == "s3" ]]; then - videoUpload () { cd "${vid_path}"; s3cmd --no-progress put "${1}" "s3://${s3_bucket}/${s3_path_vid}/"; notify-send -a "teiler" "Video Uploaded" "${s3_http_vid}/${1}"; echo -n "${s3_http_vid}/${1}" | xclip; x_clip; } +if [[ -f "${source_path}/${item_target}" ]]; then + source "${source_path}/${item_target}" else - videoUpload () { echo "No video uploader set. Check example config"; } + target_type="${item_target}" fi +source "${source_path}/teiler.conf" -# text -if [[ $paste_ul == "fb" ]]; then - clipUpload () { cd "${paste_path}"; fb "${1}"; x_clip; notify-send -a "teiler" "Paste Uploaded" "$(xclip -o)"; } -elif [[ $paste_ul == "scp" ]]; then - clipUpload () { scpUpload "Paste" "${paste_path}" "$1" "${scp_host}" "${scp_path_paste}" "${http_paste}"; } -elif [[ $paste_ul == "ix" ]]; then - clipUpload () { xclip -o 2>&1 | curl -F 'f:1=<-' ix.io | tr -d "\n" | xclip; x_clip; notify-send -a "teiler" "Paste Uploaded" "$(xclip -o)"; } -else - clipUpload () { echo "No text uploader set. Check example config"; } -fi - -scpUpload() { - fileType="$1"; - path="$2"; - filename="$3"; - scp_host="$4"; - scp_path="$5"; - http="$6"; - cd "${path}"; - scpResult="$(scp "$filename" "${scp_host}:/${scp_path}/${filename}" 2>&1)"; - if [[ "$?" == 0 ]]; then - notify-send -a "teiler" "${fileType} Uploaded" "${http}/${filename}"; - echo -n "${http}/${filename}" | xclip; - x_clip; - else - notify-send -a "teiler" "${fileType} upload failed" "$scpResult"; - fi; +scpCmd () { + scp "${item_path}" "${scp_options}" "${1}/${item_basename}" + if [[ "${save_filepath}" == "yes" ]]; then + echo "${2}" | sed "s/{filepath}/${item_basename}/" | xclip -selection clipboard + fi + notify-send -a "teiler" -t 1000 "Uploaded!" "${2}" } -x_clip () { - if [[ $img_ul == "imgur" ]]; then - (xclip -o -selection clipboard) | xclip - else - (xclip -o) | xclip -selection clipboard +s3cmdCmd () { + s3cmd --no-progress "${s3cmd_options}" put "${item_path}" "${1}/${item_basename}" + if [[ "${save_filepath}" == "yes" ]]; then + echo "${2}" | sed "s/{filepath}/${item_basename}/" | xclip -selection clipboard fi + notify-send -a "teiler" -t 1000 "Uploaded!" "${2}" } -if [[ $1 == "--upload" ]]; then - files=$(echo "$@" | cut -d ' ' -f3-) - if [[ $2 == "image" ]]; then imageUpload "${files}" - elif [[ $2 == "video" ]]; then videoUpload "${files}" - elif [[ $2 == "text" ]]; then clipUpload "${files}" + +ixioCmd () { + url=$(curl -F "f:1=@${item_path}" ix.io) + extention=$(echo "${item_path}" | sed -E 's/^.*\.(\w+)$/\1/') + lang=$(cat "${source_path}/pygmentize_types.txt" | sed -n -E "s/^(.*)\s+\.${extention}\$/\1/p") + if [[ "$lang" == "text" ]]; then + lang="" fi + # Generated filename: always copy path to clipboard + echo "${url}/${lang}" | xclip -selection clipboard + notify-send -a "teiler" -t 1000 "Uploaded!" "${url}/${lang}" +} + +imgurCmd () { + # Generated filename: imgurbash2 save in clipboard itself + url=$(imgurbash2 "${item_path}" | sed -E 's/^(\S+).*$/\1/') + notify-send -a "teiler" -t 1000 "Uploaded!" "${url}" +} + +if [[ "$target_type" == "scp" ]]; then + case "$item_type" in + Image) scpCmd "${scp_image_path}" "${scp_image_filepath}"; exit;; + Video) scpCmd "${scp_video_path}" "${scp_video_filepath}"; exit;; + Text) scpCmd "${scp_text_path}" "${scp_text_filepath}"; exit;; + esac + exit +elif [[ "$target_type" == "s3" ]]; then + case "$item_type" in + Image) s3cmdCmd "${s3cmd_image_path}" "${s3cmd_image_filepath}"; exit;; + Video) s3cmdCmd "${s3cmd_video_path}" "${s3cmd_video_filepath}"; exit;; + Text) s3cmdCmd "${s3cmd_text_path}" "${s3cmd_text_filepath}"; exit;; + esac + exit +elif [[ "$target_type" == "imgur" ]]; then + echo "Wtf 4" >> ~/teiler.log # debug + case "$item_type" in + Image) imgurCmd; exit;; + esac + exit +elif [[ "$target_type" == "ix.io" ]]; then + case "$item_type" in + Text) ixioCmd; exit;; + esac + exit fi diff --git a/uploader/s3 b/uploader/s3 deleted file mode 100755 index 7f7a02b..0000000 --- a/uploader/s3 +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -s3_bucket= -s3_path_img=path/to/images -s3_path_vid=path/to/videos -s3_path_paste=path/to/pastes -s3_http_img=http://S3_DOMAIN/path/to/images -s3_http_vid=http://S3_DOMAIN/path/to/videos -s3_http_paste=http://S3_DOMAIN/path/to/pastes diff --git a/uploader/scp b/uploader/scp deleted file mode 100755 index c53584d..0000000 --- a/uploader/scp +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -scp_host=HOSTNAME -scp_path_img=/path/to/images -scp_path_vid=/path/to/videos -scp_path_paste=/path/to/pastes -http_img=https://YOUR_DOMAIN/path/to/images -http_vid=https://YOUR_DOMAIN/path/to/videos -http_paste=https://YOUR_DOMAIN/path/to/pastes From 52a5260fb1c3dc40ddd3d5d6559767bb0a90e98d Mon Sep 17 00:00:00 2001 From: Denis Kalyuzhnyy Date: Tue, 29 Dec 2020 10:04:13 +0300 Subject: [PATCH 2/6] Move to Heyteiler --- Makefile | 16 ++--- README.md | 116 +++++++++++++++++++++++------- choises.png | Bin 0 -> 17135 bytes teiler => heyteiler | 110 ++++++++++++++-------------- teiler.conf => heyteiler.conf | 19 ++--- teiler_helper => heyteiler_helper | 14 ++-- screenshot.png | Bin 14834 -> 25969 bytes targets/local | 2 +- targets/s3 | 2 +- targets/scp | 2 +- 10 files changed, 173 insertions(+), 108 deletions(-) create mode 100644 choises.png rename teiler => heyteiler (83%) rename teiler.conf => heyteiler.conf (63%) rename teiler_helper => heyteiler_helper (83%) diff --git a/Makefile b/Makefile index b9d6d1c..17c11db 100644 --- a/Makefile +++ b/Makefile @@ -3,11 +3,11 @@ ifndef PREFIX endif install: - install -Dm755 teiler $(DESTDIR)$(PREFIX)/bin/teiler - install -Dm644 README.md $(DESTDIR)$(PREFIX)/share/doc/teiler/README.md - install -Dm644 teiler.conf $(DESTDIR)/etc/teiler/teiler.conf - install -Dm755 teiler_helper $(DESTDIR)/etc/teiler/teiler_helper - install -Dm644 pygmentize_types.txt $(DESTDIR)/etc/teiler/pygmentize_types.txt - install -Dm644 targets/local $(DESTDIR)/etc/teiler/targets/local - install -Dm644 targets/s3 $(DESTDIR)/etc/teiler/targets/s3 - install -Dm644 targets/scp $(DESTDIR)/etc/teiler/targets/scp + install -Dm755 heyteiler $(DESTDIR)$(PREFIX)/bin/heyteiler + install -Dm644 README.md $(DESTDIR)$(PREFIX)/share/doc/heyteiler/README.md + install -Dm644 heyteiler.conf $(DESTDIR)/etc/heyteiler/heyteiler.conf + install -Dm755 heyteiler_helper $(DESTDIR)/etc/heyteiler/heyteiler_helper + install -Dm644 pygmentize_types.txt $(DESTDIR)/etc/heyteiler/pygmentize_types.txt + install -Dm644 targets/local $(DESTDIR)/etc/heyteiler/targets/local + install -Dm644 targets/s3 $(DESTDIR)/etc/heyteiler/targets/s3 + install -Dm644 targets/scp $(DESTDIR)/etc/heyteiler/targets/scp diff --git a/README.md b/README.md index 6914174..3e7d135 100644 --- a/README.md +++ b/README.md @@ -1,38 +1,106 @@ # heyteiler - a little screenshot tool written in bash -heyteiler (forked from [teiler](https://github.com/carnager/teiler)) uses rofi to draw a menu which lets you -choose between screenshots or screencasts. +heyteiler (forked from [teiler](https://github.com/carnager/teiler)) uses rofi +to draw a menu which lets you choose between screenshots, screencasts, +saveclipboard or recognize text. ## Screenshot -![teiker](screenshot.png "heyteiler in action") +![mainMenu](screenshot.png "heyteiler in action") ## Features -* screenshots fullscreen/monitor/area -* delay of screenshots -* screencasts of monitor/area -* upload screenshots/screencasts - teiler can also upload your files via scp, imgur or filebin, ix (for pastes) and amazon s3. -* History of Images and Videos with support for +* Screenshots fullscreen all/fullscreen/area +* Screencasts of fullscreen/area +* Save clipboard text in file +* Recognize text and put it in clipboard +* Delay screenshots +* Save screenshots in clipboard +* Save filepath of result in clipboard +* Upload your files via: + - imgur (only images, require: [imgurbash2](https://github.com/ram-on/imgurbash2)) + - ix (only text) + - scp (all formats, require: openssh) + - amazon s3 (all formats, require: s3cmd cli tool) +* History of Images,Videos and Text with support for + Viewing - + Editing + Uploading -* Commandline interface for direct access to all features. Useful for hotkeys -* Recognize text and put it in clipboard +* Commandline interface for direct access to all features: useful for hotkeys of + if your don't want to use rofi + +## Configuration + +Default system configuration storied in the `/etc/heytiler` directory. But for +user defined changes i recommend to copy `/etc/heytiler` folder in user +`$HOME/.config/heytiler` directory + +```bash +cp -R /etc/heytiler ~/.config/heyteiler +``` + +Here you find: + - heyteiler.conf - main configuration file + - targets - folder with targets configuration files + +## Choises +Some menus has choises in header. For change values in them use rofi keybinds: Alt+1, +Alt+2, Alt+3 + +![choises](choises.png "heyteiler menu with choises") + +## Targets + +Targets is main feature of heyteiler. In config directory, you may find targets +folder. Every file in this folder describe one target. +You may change exist target or create your own just copy one of existing. +See `targets` files for more options + +Supported `target_type`: 'local', 'scp', 'imgur', 'clipboard' + - Images: local, clipboard, scp, s3, imgur + - Video: local, scp, s3 + - Text: s3, scp, ix.io + +imgur and ix.io target types worked without any additional settings. So, they +haven't special file. But if you want to change local directory for backups you +may copy `local` target and set `target_type=imgur`. + +```bash +cd ~/.config/heyteiler/targets +cp local my_custom_imgur +sed -i 's/target_type=.*/target_type=imgur/' my_custom_imgur +# Change imgur backup directory +sed -i 's/Screenshots/Imgur/' my_custom_imgur +``` + +### Local target + +*DONT REMOVE LOCAL TARGET* + +`local` target is a special target which heyteiler use for saving files before +upload on the resource. So even if you use network resource as a target (ex: +imgur or scp) your file will be available in future in `local` target folders or in +history tab. + +Also `local` target used for openning files from history. + ## Dependencies: -* xininfo (https://github.com/DaveDavenport/xininfo) -* rofi (https://github.com/DaveDavenport/rofi) -* ffmpeg (http://www.ffmpeg.org) * xclip -* maim (https://github.com/naelstrof/maim) * slop (https://github.com/naelstrof/slop) -* tesseract (https://github.com/tesseract-ocr/tesseract) -* ImageMagic - -## Optional Dependencies - -* imgurbash2 (https://github.com/ram-on/imgurbash2) -* openssh (http://www.openssh.com) -* ix (http://ix.io) -* s3 cli tools +* xdg-open +* UI dependency: + * rofi (https://github.com/DaveDavenport/rofi) +* Screenshot dependency + * maim (https://github.com/naelstrof/maim) +* Screencasts dependencies: + * xininfo (https://github.com/DaveDavenport/xininfo) + * ffmpeg (http://www.ffmpeg.org) +* Recognize dependencies: + * maim + * tesseract (https://github.com/tesseract-ocr/tesseract) + * ImageMagic (https://imagemagick.org/index.php) +* Uploading dependencies: + * curl + * imgurbash2 (https://github.com/ram-on/imgurbash2) + * openssh (http://www.openssh.com) + * s3 cli tools diff --git a/choises.png b/choises.png new file mode 100644 index 0000000000000000000000000000000000000000..16860df7361099e1797e93562d0fd1489788c776 GIT binary patch literal 17135 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 z" \ "$screencast_menu" \ "[ SaveClipboard ]>" \ @@ -182,7 +190,6 @@ screenshotMenu () { "Return") mainMenu && exit;; esac - echo "${target_type}" # Save image to clipboard and exit if [[ "${target_type}" == "clipboard" ]]; then maimCmd "${delay}" "-" "${mode}" | xclip -selection clipboard -t image/png @@ -192,7 +199,7 @@ screenshotMenu () { maimCmd "${delay}" "${image_path}/${image_filename}" "${mode}" saveInHistory Image "${image_path}/${image_filename}" if [[ "$target_type" != "local" ]]; then - "${source_path}/teiler_helper" Image "${image_path}/${image_filename}" "${source_path}" "${image_target}" + _heyteiler_helper Image "${image_path}/${image_filename}" "${source_path}" "${image_target}" elif [[ "$save_filepath" == "yes" ]]; then echo "${img_output}" | xclip -selection clipboard fi @@ -232,7 +239,7 @@ targetPrompt () { # Source target if [[ -f "${source_path}/targets/${result_target}" ]]; then source "${source_path}/targets/${result_target}" - source "${source_path}/teiler.conf" + source "${source_path}/heyteiler.conf" else target_type="${result_target}" fi @@ -278,7 +285,7 @@ screencastMenu () { stopRecording saveInHistory Video "${video_filepath}" if [[ "$video_target" != "local" ]]; then - "${source_path}/teiler_helper" Video "$video_filepath" "${source_path}" "${video_target}" + _heyteiler_helper Video "$video_filepath" "${source_path}" "${video_target}" elif [[ "$save_filepath" == "yes" ]]; then echo "$video_filepath" | xclip -selection clipboard fi @@ -292,7 +299,7 @@ screencastMenu () { "Target") targetPrompt Video && screencastMenu && exit;; "Return") mainMenu && exit;; esac - echo "$video_target" > "$teiler_target_file" + echo "$video_target" > "$heyteiler_target_file" ffmpegCmd "${video_path}/${video_filename}" $mode } @@ -318,7 +325,7 @@ clipboardMenu () { clipboardCmd "${_text_output}" saveInHistory Text "${_text_output}" if [[ "$target_type" != "local" ]]; then - "${source_path}/teiler_helper" Text "${_text_output}" "${source_path}" "${text_target}" + _heyteiler_helper Text "${_text_output}" "${source_path}" "${text_target}" # TODO elif [[ "$save_filepath" == "yes" ]]; then echo "${_text_output}" | xclip -selection clipboard @@ -348,7 +355,7 @@ typeHistoryMenu () { history_target="${text_target}" fi - _history_items=$( grep "${_history_type}" "${teiler_history_file}" | sed "s/${_history_type}\s\+//" | sed ':a;N;$!ba;s/\n/ /g') + _history_items=$( grep "${_history_type}" "${heyteiler_history_file}" | sed "s/${_history_type}\s\+//" | sed ':a;N;$!ba;s/\n/ /g') menu=$(showMenu "History ${_history_type}" ${_history_items} - Target ${history_target}) case "${menu}" in Target) targetPrompt "${_history_type}" && typeHistoryMenu "${_history_type}" && exit;; @@ -358,54 +365,51 @@ typeHistoryMenu () { if [[ "$target_type" == "local" ]]; then xdg-open "${menu}" - # Only images has target: clipboard in teiler + # Only images has target: clipboard in heyteiler elif [[ "$target_type" == "clipboard" ]]; then cat "${menu}" | xclip -selection clipboard -t image/png else - "${source_path}/teiler_helper" "${_history_type}" "${menu}" "${source_path}" "${history_target}" + _heyteiler_helper "${_history_type}" "${menu}" "${source_path}" "${history_target}" fi } saveInHistory () { _history_type="${1}" _item_path="${2}" - _history_tmp_file="${teiler_history_file}.tmp" + _history_tmp_file="${heyteiler_history_file}.tmp" echo "${_history_type} ${_item_path}" > "${_history_tmp_file}" - if [[ -f "${teiler_history_file}" ]]; then - head -199 "${teiler_history_file}" >> "${_history_tmp_file}" + if [[ -f "${heyteiler_history_file}" ]]; then + head -199 "${heyteiler_history_file}" >> "${_history_tmp_file}" fi - mv "${_history_tmp_file}" "${teiler_history_file}" + mv "${_history_tmp_file}" "${heyteiler_history_file}" } stopRecording () { - # TODO - echo "im here" - video_filepath="$(cat "${teiler_name_file}")" - video_pid="$(cat "${teiler_pid_file}")" - video_old_resolution="$(cat "${teiler_resolution_file}")" - video_target="$(cat "${teiler_target_file}")" + video_filepath="$(cat "${heyteiler_name_file}")" + video_pid="$(cat "${heyteiler_pid_file}")" + video_old_resolution="$(cat "${heyteiler_resolution_file}")" + video_target="$(cat "${heyteiler_target_file}")" if [[ -z "$video_filepath" ]] ||\ [[ -z "$video_old_resolution" ]] ||\ [[ -z "$video_target" ]]; then _witherrors=" with errors" - rm -f "$teiler_name_file" - rm -f "$teiler_resolution_file" - rm -f "$teiler_target_file" + rm -f "$heyteiler_name_file" + rm -f "$heyteiler_resolution_file" + rm -f "$heyteiler_target_file" fi - if [[ -f "${teiler_pid_file}" ]]; then - echo "tested pid: $(ps -p $video_pid)" >> ~/teiler.log + if [[ -f "${heyteiler_pid_file}" ]]; then if [[ -n "$(pgrep ffmpeg | grep "$video_pid")" ]]; then kill "$video_pid" else _witherrors=" with errors" fi - rm -f "${teiler_pid_file}" + rm -f "${heyteiler_pid_file}" fi - notify-send -a "teiler" -t 1000 "teiler" "Stopped recording${_witherrors}" + notify-send -a "heyteiler" -t 1000 "heyteiler" "Stopped recording${_witherrors}" output=$(xininfo -name); xrandr --output "$output" --mode "$video_old_resolution"; - rm -f "${teiler_resolution_file}"; + rm -f "${heyteiler_resolution_file}"; } @@ -420,7 +424,7 @@ ffmpegCmd () { # Prepare resolution resolution_now="$(xininfo -mon-size | sed 's/ /x/')" - echo "$resolution_now" > "${teiler_resolution_file}" + echo "$resolution_now" > "${heyteiler_resolution_file}" if [[ -z "$resolution" ]]; then resolution="$resolution_now" fi @@ -433,26 +437,24 @@ ffmpegCmd () { sleep 5; fi - echo "${video_output}" > "${teiler_name_file}" # Safe video name for next time + echo "${video_output}" > "${heyteiler_name_file}" # Safe video name for next time if [[ "$2" == "fullscreen" ]]; then ffmpeg_display_opts="-s $resolution -i $(echo $DISPLAY)+$(xininfo -mon-x),$(xininfo -mon-y)" ffmpeg -f x11grab $ffmpeg_display_opts \ ${ffmpeg_video_fullscreen} "${video_output}" & - echo "$!" > "${teiler_pid_file}" - notify-send -a "teiler" -t 1000 "teiler" "Screencast started" + echo "$!" > "${heyteiler_pid_file}" + notify-send -a "heyteiler" -t 1000 "heyteiler" "Screencast started" elif [[ $2 == "area" ]]; then read -r X Y W H G ID < <(slop ${slop_options} -f "%x %y %w %h %g %i") X=$(round $X) Y=$(round $Y) W=$(round $W) H=$(round $H) - echo "size: $X $Y $W $H" >> ~/t1iler.log # debug ffmpeg_display_opts="-s "$W"x"$H" -i $(echo $DISPLAY)+$X,$Y)" ffmpeg -show_region 1 -f x11grab $ffmpeg_display_opts \ ${ffmpeg_video_area} "${video_output}" & - echo "$!" > "${teiler_pid_file}" - notify-send -a "teiler" -t 1000 "teiler" "Screencast started" - # TODO: Run slop again? + echo "$!" > "${heyteiler_pid_file}" + notify-send -a "heyteiler" -t 1000 "heyteiler" "Screencast started" fi } @@ -463,7 +465,7 @@ tesseractCmd () { # tesseract always wait colored on white images convert - -set colorspace Gray -separate -average -negate - | tesseract -l "$recognize_language" - - -c page_separator="" | xclip -selection clipboard fi - notify-send -a "teiler" -t 1000 "teiler" "Recognition done!" + notify-send -a "heyteiler" -t 1000 "heyteiler" "Recognition done!" } maimCmd () { @@ -504,7 +506,7 @@ maimCmd () { maim ${maim_mode_options} ${maim_delay} ${maim_cursor} ${img_output} if [[ "${1}" != "0" ]]; then - notify-send -a "teiler" -t 1000 "teiler" "Chick!"; + notify-send -a "heyteiler" -t 1000 "heyteiler" "Chick!"; fi } @@ -517,7 +519,7 @@ delayPrompt () { echo_help () { cat << EOF -teiler - a rofi-driven screen{shot,cast} utility +heyteiler - a rofi-driven screen{shot,cast} utility screenshot [quick] [target] [delay] open screenshots menu/make quick screenshot to target diff --git a/teiler.conf b/heyteiler.conf similarity index 63% rename from teiler.conf rename to heyteiler.conf index 97941f1..f30fc4d 100644 --- a/teiler.conf +++ b/heyteiler.conf @@ -1,27 +1,24 @@ -##### teiler configuration file ###### +##### heyteiler configuration file ###### ### Screenshots Settings ### # This destination used as default (One from: ./targets) -# Possible target_type var: local, clipboard, filebin, scp, s3, imgur +# Possible target_type var: local, clipboard, scp, s3, imgur default_image_target=local # Filemask for created image files. image_filename="image-$(date +'%Y-%m-%d-%H%M%S').png" - ### Screencasts Settings ### # This destination used as default (one from ./targets) -# Possible target_type var: local, filebin, scp, s3 +# Possible target_type var: local, scp, s3 default_video_target=local -# Filemask for created video files. See ~/.config/teiler/targets for ${ffmpeg_type} value +# Filemask for created video files. See ~/.config/heyteiler/targets for ${ffmpeg_type} value video_filename="video-$(date +'%Y-%m-%d-%H%M%S').${ffmpeg_type}" -# Pidfile -video_pidfile=/tmp/$USER-teiler-screencast.pid ### Save Clipboard Settings ### -# This destination used as default (use one from ~/.config/teiler/destination) -# Possible Choices for paste: fb, scp, ix.io +# This destination used as default (use one from ~/.config/heyteiler/destination) +# Possible Choices for paste: s3, scp, ix.io default_text_target=local -# Filemask for created text files. See ~/.config/teiler/targets for ${ffmpeg_type} value +# Filemask for created text files. See ~/.config/heyteiler/targets for ${ffmpeg_type} value text_filename="text-$(date +'%Y-%m-%d-%H%M%S').txt" ### Recognition Settings ### @@ -29,8 +26,6 @@ text_filename="text-$(date +'%Y-%m-%d-%H%M%S').txt" # languages but i'm not recommend it default_recognize_language="eng" -### History Settings ### - ### Advanced variables ### # Save filepath in clipboard save_filepath=yes diff --git a/teiler_helper b/heyteiler_helper similarity index 83% rename from teiler_helper rename to heyteiler_helper index 8861fd4..de186ea 100755 --- a/teiler_helper +++ b/heyteiler_helper @@ -1,7 +1,7 @@ #!/usr/bin/env bash # Example -# teiler_helper image "${image_path}/${image_filename}" "${source_path}" "${image_target}" +# heyteiler_helper image "${image_path}/${image_filename}" "${source_path}" "${image_target}" echo "vars: $@" # debug item_type="${1}" @@ -16,14 +16,14 @@ if [[ -f "${source_path}/${item_target}" ]]; then else target_type="${item_target}" fi -source "${source_path}/teiler.conf" +source "${source_path}/heyteiler.conf" scpCmd () { scp "${item_path}" "${scp_options}" "${1}/${item_basename}" if [[ "${save_filepath}" == "yes" ]]; then echo "${2}" | sed "s/{filepath}/${item_basename}/" | xclip -selection clipboard fi - notify-send -a "teiler" -t 1000 "Uploaded!" "${2}" + notify-send -a "heyteiler" -t 1000 "Uploaded!" "${2}" } s3cmdCmd () { @@ -31,7 +31,7 @@ s3cmdCmd () { if [[ "${save_filepath}" == "yes" ]]; then echo "${2}" | sed "s/{filepath}/${item_basename}/" | xclip -selection clipboard fi - notify-send -a "teiler" -t 1000 "Uploaded!" "${2}" + notify-send -a "heyteiler" -t 1000 "Uploaded!" "${2}" } @@ -44,13 +44,13 @@ ixioCmd () { fi # Generated filename: always copy path to clipboard echo "${url}/${lang}" | xclip -selection clipboard - notify-send -a "teiler" -t 1000 "Uploaded!" "${url}/${lang}" + notify-send -a "heyteiler" -t 1000 "Uploaded!" "${url}/${lang}" } imgurCmd () { # Generated filename: imgurbash2 save in clipboard itself url=$(imgurbash2 "${item_path}" | sed -E 's/^(\S+).*$/\1/') - notify-send -a "teiler" -t 1000 "Uploaded!" "${url}" + notify-send -a "heyteiler" -t 1000 "Uploaded!" "${url}" } if [[ "$target_type" == "scp" ]]; then @@ -68,7 +68,7 @@ elif [[ "$target_type" == "s3" ]]; then esac exit elif [[ "$target_type" == "imgur" ]]; then - echo "Wtf 4" >> ~/teiler.log # debug + echo "Wtf 4" >> ~/heyteiler.log # debug case "$item_type" in Image) imgurCmd; exit;; esac diff --git a/screenshot.png b/screenshot.png index cbbb6cc4d9e70b9a2265a6e6752a87e7a26dc3b5..cc62bdf76c05512de2e721e9ecbf7a44192d994c 100644 GIT binary patch literal 25969 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 diff --git a/targets/local b/targets/local index 5c137d6..5991012 100644 --- a/targets/local +++ b/targets/local @@ -12,7 +12,7 @@ text_path="$HOME/Documents/ClipboardSaves/$(date +'%m.%Y')" # It may be usefull to change qulity of screencast for diffrent targets # If you don't care about video size just don't touch this settings :) -# Only for filename, see video_filemask in ~/.config/teiler/config +# Only for filename, see video_filemask in ~/.config/heyteiler/config ffmpeg_type="mp4" # ffmpeg video capture settings for fullscreen mode (read more in ffmpeg docs) ffmpeg_video_fullscreen="-f pulse -ac 2 -i default -r 30 -c:v libx264 -preset slow -crf 18 -c:a libvorbis " diff --git a/targets/s3 b/targets/s3 index ec03494..efbfe38 100755 --- a/targets/s3 +++ b/targets/s3 @@ -22,7 +22,7 @@ s3cmd_text_filepath="${s3cmd_text_path}/{filename}" # It may be usefull to change qulity of screencast for diffrent targets # If you don't care about video size just don't touch this settings :) -# Only for filename, see video_filemask in ~/.config/teiler/config +# Only for filename, see video_filemask in ~/.config/heyteiler/config ffmpeg_type="mp4" # ffmpeg video capture settings for fullscreen mode (read more in ffmpeg docs) ffmpeg_video_fullscreen="-f pulse -ac 2 -i default -r 30 -c:v libx264 -preset slow -crf 18 -c:a libvorbis " diff --git a/targets/scp b/targets/scp index 19cebf9..e72c009 100644 --- a/targets/scp +++ b/targets/scp @@ -22,7 +22,7 @@ scp_text_filepath="${scp_text_path}/{filename}" # It may be usefull to change qulity of screencast for diffrent targets # If you don't care about video size just don't touch this settings :) -# Only for filename, see video_filemask in ~/.config/teiler/config +# Only for filename, see video_filemask in ~/.config/heyteiler/config ffmpeg_type="mp4" # ffmpeg video capture settings for fullscreen mode (read more in ffmpeg docs) ffmpeg_video_fullscreen="-f pulse -ac 2 -i default -r 30 -c:v libx264 -preset slow -crf 18 -c:a libvorbis " From e5fc1f66388c5e24110747eddd2e58108dc5f318 Mon Sep 17 00:00:00 2001 From: Denis Kalyuzhnyy Date: Tue, 29 Dec 2020 10:20:44 +0300 Subject: [PATCH 3/6] [f] Return from target menu --- heyteiler | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/heyteiler b/heyteiler index 8137a64..50ccb74 100755 --- a/heyteiler +++ b/heyteiler @@ -210,7 +210,7 @@ targetPrompt () { if [[ "$_prompt_type" == "Image" ]]; then _posible_target_types="local|scp|s3|imgur|clipboard" # Types allowed without any settings - _default_target_types="imgur|filebin|clipboard" + _default_target_types="imgur|clipboard" elif [[ "$_prompt_type" == "Video" ]]; then _posible_target_types="local|scp|s3" _default_target_types="" @@ -236,6 +236,10 @@ targetPrompt () { fi result_target=$(echo -e "$_targets" | _rofi -dmenu -p "${_prompt_type} Target >") + val=$? + if [[ "$val" != 0 ]]; then + return + fi # Source target if [[ -f "${source_path}/targets/${result_target}" ]]; then source "${source_path}/targets/${result_target}" From fd91d9d70c5580fbc7d018d806b38e4f9b75c54e Mon Sep 17 00:00:00 2001 From: Denis Kalyuzhnyy Date: Tue, 29 Dec 2020 15:41:15 +0300 Subject: [PATCH 4/6] [+] command line utility --- heyteiler | 227 +++++++++++++++++++++++++++++++++-------------- heyteiler_helper | 14 +-- 2 files changed, 167 insertions(+), 74 deletions(-) diff --git a/heyteiler b/heyteiler index 50ccb74..dc720c4 100755 --- a/heyteiler +++ b/heyteiler @@ -180,15 +180,25 @@ mainMenu () { } screenshotMenu () { - menu=$(showMenu Screenshot Area Fullscreen "Fullscreen All" - Target "${image_target}" Delay "${delay}") - case "${menu}" in - "Area") mode="area";; - "Fullscreen") mode="fullscreen";; - "Fullscreen All") mode="fullscreenAll";; - "Target") targetPrompt Image && screenshotMenu && exit;; - "Delay") delayPrompt && screenshotMenu && exit;; - "Return") mainMenu && exit;; - esac + if [[ "${1}" == "quick" ]]; then + mode="${2}" + targetPrompt Image quick "${3}" + if [[ -n "${4}" ]]; then + delay="${4}" + else + delay=0 + fi + else + menu=$(showMenu Screenshot Area Fullscreen "Fullscreen All" - Target "${image_target}" Delay "${delay}") + case "${menu}" in + "Area") mode="area";; + "Fullscreen") mode="fullscreen";; + "Fullscreen All") mode="fullscreenAll";; + "Target") targetPrompt Image && screenshotMenu && exit;; + "Delay") delayPrompt && screenshotMenu && exit;; + "Return") mainMenu && exit;; + esac + fi # Save image to clipboard and exit if [[ "${target_type}" == "clipboard" ]]; then @@ -221,25 +231,27 @@ targetPrompt () { exit fi - __sed_added=$(echo -n "${_default_target_types}" | sed "s/|/\\\\n/g") - - _targets=$(grep -l -R -E "target_type=(${_posible_target_types})" ./targets |\ - sed 's%./targets/%%' - ) - - # Ensure that default targets only added only one time - if [[ -n "${__sed_added}" ]]; then - _targets=$(echo "$_targets" |\ - grep -v -E "${_default_target_types}" |\ - sed -e "\$a${__sed_added}" + if [[ "${2}" == "quick" ]]; then + result_target="${3}" + else + __sed_added=$(echo -n "${_default_target_types}" | sed "s/|/\\\\n/g") + _targets=$(grep -l -R -E "target_type=(${_posible_target_types})" ./targets |\ + sed 's%./targets/%%' ) + # Ensure that default targets only added only one time + if [[ -n "${__sed_added}" ]]; then + _targets=$(echo "$_targets" |\ + grep -v -E "${_default_target_types}" |\ + sed -e "\$a${__sed_added}" + ) + fi + result_target=$(echo -e "$_targets" | _rofi -dmenu -p "${_prompt_type} Target >") + val=$? + if [[ "$val" != 0 ]]; then + return + fi fi - result_target=$(echo -e "$_targets" | _rofi -dmenu -p "${_prompt_type} Target >") - val=$? - if [[ "$val" != 0 ]]; then - return - fi # Source target if [[ -f "${source_path}/targets/${result_target}" ]]; then source "${source_path}/targets/${result_target}" @@ -259,13 +271,30 @@ targetPrompt () { # Recognition recognitionMenu () { - menu=$(showMenu Colors "Colored on White" "Colored on Dark" - Language "$recognize_language") - case "${menu}" in - "Colored on White") colors="whiteback";; - "Colored on Dark") colors="darkback";; - "Language") languagePrompt && recognitionMenu && exit;; - "Return") mainMenu && exit;; - esac + if [[ "${1}" == "quick" ]] || [[ "${1}" == "q" ]]; then + case "${2}" in + w|white|whiteback) colors="whiteback";; + d|dark|darkback|b|black|blackback) colors="darkback";; + esac + if [[ -n "${3}" ]]; then + recognize_language="${3}" + else + recognize_language="${default_recognize_language}" + fi + if [[ -n "${4}" ]]; then + delay="${4}" + else + delay=0 + fi + else + menu=$(showMenu Colors "Colored on White" "Colored on Dark" - Language "$recognize_language") + case "${menu}" in + "Colored on White") colors="whiteback";; + "Colored on Dark") colors="darkback";; + "Language") languagePrompt && recognitionMenu && exit;; + "Return") mainMenu && exit;; + esac + fi maimCmd 0 - area | tesseractCmd $colors; } @@ -284,7 +313,7 @@ test_xrandr () { } screencastMenu () { - # Stop recording if it run + # Stop recording if it run and exit if [[ "$video_recording" == "yes" ]]; then stopRecording saveInHistory Video "${video_filepath}" @@ -296,13 +325,18 @@ screencastMenu () { exit fi - menu=$(showMenu Screencast Area Fullscreen - Target "$video_target") # TODO: choose audio inputs - case "${menu}" in - "Area") mode="area";; - "Fullscreen") mode="fullscreen";; - "Target") targetPrompt Video && screencastMenu && exit;; - "Return") mainMenu && exit;; - esac + if [[ "${1}" == "quick" ]] || [[ "${1}" == "q" ]]; then + mode="${2}" + targetPrompt Video quick "${3}" + else + menu=$(showMenu Screencast Area Fullscreen - Target "$video_target") # TODO: choose audio inputs + case "${menu}" in + "Area") mode="area";; + "Fullscreen") mode="fullscreen";; + "Target") targetPrompt Video && screencastMenu && exit;; + "Return") mainMenu && exit;; + esac + fi echo "$video_target" > "$heyteiler_target_file" ffmpegCmd "${video_path}/${video_filename}" $mode } @@ -314,13 +348,21 @@ clipboardMenu () { fi _texttypes=$(cat "${source_path}/pygmentize_types.txt" | awk '{print $1}' | sed ':a;N;$!ba;s/\n/ /g') - # _cliptext=$(xclip -o -selection clipboard) - menu=$(showMenu "Text Format" $_texttypes - Target "$text_target") - case "${menu}" in - Target) targetPrompt Text && clipboardMenu && exit;; - Return) mainMenu && exit;; - *) _filetype="${menu}";; - esac + if [[ "${1}" == "quick" ]] || [[ "${1}" == "q" ]]; then + targetPrompt Text quick "${2}" + if [[ -n "${3}" ]]; then + _filetype="${3}" + else + _filetype="text" + fi + else + menu=$(showMenu "Text Format" $_texttypes - Target "$text_target") + case "${menu}" in + Target) targetPrompt Text && clipboardMenu && exit;; + Return) mainMenu && exit;; + *) _filetype="${menu}";; + esac + fi _file_extention=$(cat "${source_path}/pygmentize_types.txt" | grep "^${_filetype}\s\+" | awk '{print $2}') # Replace extention _text_output=$(echo "${text_path}/${text_filename}" |\ @@ -359,13 +401,23 @@ typeHistoryMenu () { history_target="${text_target}" fi - _history_items=$( grep "${_history_type}" "${heyteiler_history_file}" | sed "s/${_history_type}\s\+//" | sed ':a;N;$!ba;s/\n/ /g') - menu=$(showMenu "History ${_history_type}" ${_history_items} - Target ${history_target}) - case "${menu}" in - Target) targetPrompt "${_history_type}" && typeHistoryMenu "${_history_type}" && exit;; - Return) mainMenu && exit;; - *) echo "";; - esac + if [[ "${2}" == "quick" ]] || [[ "${2}" == "q" ]]; then + # Set target + targetPrompt "${_history_type}" "quick" "${3}" + # Set last item + menu=$( grep "${_history_type}" "${heyteiler_history_file}" |\ + sed "s/${_history_type}\s\+//" |\ + head -1 + ) + else + _history_items=$( grep "${_history_type}" "${heyteiler_history_file}" | sed "s/${_history_type}\s\+//" | sed ':a;N;$!ba;s/\n/ /g') + menu=$(showMenu "History ${_history_type}" ${_history_items} - Target "${history_target}") + case "${menu}" in + Target) targetPrompt "${_history_type}" && typeHistoryMenu "${_history_type}" && exit;; + Return) mainMenu && exit;; + *) echo "";; + esac + fi if [[ "$target_type" == "local" ]]; then xdg-open "${menu}" @@ -522,29 +574,70 @@ delayPrompt () { } echo_help () { +targets_names=$(ls -1 "${source_path}/targets" |\ + grep -v 'clipboard|imgur|ix.io' |\ + sed '$aclipboard\nimgur\nix.io' |\ + sed ':a;N;$!ba;s/\n/ /g') +tlangs=$(tesseract --list-langs |\ + grep -v ' ' |\ + sed ':a;N;$!ba;s/\n/ /g') + cat << EOF heyteiler - a rofi-driven screen{shot,cast} utility -screenshot [quick] [target] [delay] +screenshot [quick mode target delay] open screenshots menu/make quick screenshot to target -screencast [quick] [target] [delay] + alias: image i +screencast [quick mode target] open screencasts menu/quick screencast start or stop -saveclipboard [quick] [target] [delay] + alias: video v +saveclipboard [quick target code] open clipboard menu/quick save clipboard to target -recognition [quick] [delay] + alias: text t +recognition [quick background language delay] open recognition menu/quick recognize text to clipboard -history [quick] [type] [target] - open history menu/quick send last item to target + alias: r +history [type] [quick target] + open history [type] menu/quick send last [type] item to target + alias: h + +Options: + quick: quick|q + mode: area fullscreen fullscreenAll + delay: any number or skip + target: ${targets_names} + code: text bash python and many more... + background: white|w dark|d + language: ${tlangs} + type: image|i video|v text|t + +Usefull examples: + # Make fullscreen screenshot with delay + heyteiler screenshot quick fullscreen local 3 + # Fast copy area to clipboard + heyteiler screenshot quick area clipboard + + # Put last screenshot image to clipboard + heyteiler history image quick clipboard + # Open last [h]istory [v]ideo [q]uick + heyteiler h v q local EOF } -case $key in - quick) cmd_quick="--quick" ; shift;; - screenshot) shift; screenshotMenu "${cmd_quick}" "$@" && exit;; - screencast) shift; screencastMenu "${cmd_quick}" "$@" && exit;; # TODO - saveclipboard) shift; clipboardMenu "${cmd_quick}" "$@" && exit;; # TODO - recognition) shift; recognitionMenu "${cmd_quick}" "$@" && exit;; # TODO - history) shift; historyMenu "${cmd_quick}" "$@" && exit;; # TODO +key="$1" +case "$key" in + screenshot|image|i) shift; screenshotMenu "$@" && exit;; + screencast|video|v) shift; screencastMenu "$@" && exit;; + saveclipboard|text|t) shift; clipboardMenu "$@" && exit;; + recognition|r) shift; recognitionMenu "$@" && exit;; # TODO: quick + history|h) shift; if [[ -z "$1" ]]; then historyMenu; exit; fi;; -h|--help) echo_help && exit;; *) mainMenu && exit;; esac + +key2="$1" +case "$key2" in + i|screenshot|image|Image) shift; typeHistoryMenu Image "$@" && exit;; + v|screencast|video|Video) shift; typeHistoryMenu Video "$@" && exit;; + t|saveclipboard|text|Text) shift; typeHistoryMenu Text "$@" && exit;; +esac diff --git a/heyteiler_helper b/heyteiler_helper index de186ea..e302962 100755 --- a/heyteiler_helper +++ b/heyteiler_helper @@ -2,8 +2,6 @@ # Example # heyteiler_helper image "${image_path}/${image_filename}" "${source_path}" "${image_target}" -echo "vars: $@" # debug - item_type="${1}" item_path="${2}" source_path="${3}" @@ -36,15 +34,17 @@ s3cmdCmd () { ixioCmd () { - url=$(curl -F "f:1=@${item_path}" ix.io) + url=$(curl --no-progress-meter -F "f:1=@${item_path}" ix.io) extention=$(echo "${item_path}" | sed -E 's/^.*\.(\w+)$/\1/') lang=$(cat "${source_path}/pygmentize_types.txt" | sed -n -E "s/^(.*)\s+\.${extention}\$/\1/p") + # Generated filename: always copy path to clipboard if [[ "$lang" == "text" ]]; then - lang="" + url="${url}" + else + url="${url}/${lang}" fi - # Generated filename: always copy path to clipboard - echo "${url}/${lang}" | xclip -selection clipboard - notify-send -a "heyteiler" -t 1000 "Uploaded!" "${url}/${lang}" + echo "${url}" | xclip -selection clipboard + notify-send -a "heyteiler" -t 1000 "Uploaded!" "${url}" } imgurCmd () { From aa3d99cac99fb560f3ba88c5aefebcad222fe1cb Mon Sep 17 00:00:00 2001 From: Denis Kalyuzhnyy Date: Wed, 30 Dec 2020 17:54:06 +0300 Subject: [PATCH 5/6] [f] filenames --- README.md | 1 + heyteiler | 24 +++++++++++------------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 3e7d135..2314dc3 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,7 @@ Also `local` target used for openning files from history. * xclip * slop (https://github.com/naelstrof/slop) * xdg-open +* libnotify * UI dependency: * rofi (https://github.com/DaveDavenport/rofi) * Screenshot dependency diff --git a/heyteiler b/heyteiler index dc720c4..7b3bc56 100755 --- a/heyteiler +++ b/heyteiler @@ -60,14 +60,14 @@ check_path () { check_filepath="$2" if [[ ! -d "$check_filepath" ]]; then read -p "${check_what} path \"${check_filepath}\" does not exist. Create it? (Y/n)" -n 1 -r + echo "REPLY: $REPLY" >> "~/teiler.log" if [[ $REPLY =~ ^[Yy]$ ]] || [[ $REPLY == "" ]]; then mkdir -p "${check_filepath}" elif [[ $REPLY =~ ^[Nn]$ ]]; then exit else - echo "Please enter y or n" - check_path - exit + # create better than not create ) + mkdir -p "${check_filepath}" fi fi } @@ -211,7 +211,7 @@ screenshotMenu () { if [[ "$target_type" != "local" ]]; then _heyteiler_helper Image "${image_path}/${image_filename}" "${source_path}" "${image_target}" elif [[ "$save_filepath" == "yes" ]]; then - echo "${img_output}" | xclip -selection clipboard + echo "${image_path}/${image_filename}" | tr -d '\n' | xclip -selection clipboard fi } @@ -235,8 +235,8 @@ targetPrompt () { result_target="${3}" else __sed_added=$(echo -n "${_default_target_types}" | sed "s/|/\\\\n/g") - _targets=$(grep -l -R -E "target_type=(${_posible_target_types})" ./targets |\ - sed 's%./targets/%%' + _targets=$(grep -l -R -E "target_type=(${_posible_target_types})" "${source_path}/targets" |\ + sed "s%${source_path}/targets/%%" ) # Ensure that default targets only added only one time if [[ -n "${__sed_added}" ]]; then @@ -320,7 +320,7 @@ screencastMenu () { if [[ "$video_target" != "local" ]]; then _heyteiler_helper Video "$video_filepath" "${source_path}" "${video_target}" elif [[ "$save_filepath" == "yes" ]]; then - echo "$video_filepath" | xclip -selection clipboard + echo "$video_filepath" | tr -d '\n' | xclip -selection clipboard fi exit fi @@ -374,7 +374,7 @@ clipboardMenu () { _heyteiler_helper Text "${_text_output}" "${source_path}" "${text_target}" # TODO elif [[ "$save_filepath" == "yes" ]]; then - echo "${_text_output}" | xclip -selection clipboard + echo "${_text_output}" | tr -d '\n' | xclip -selection clipboard fi } @@ -516,10 +516,10 @@ ffmpegCmd () { tesseractCmd () { if [[ "$1" == "whiteback" ]]; then - tesseract -l "$recognize_language" - - -c page_separator="" | xclip -selection clipboard + tesseract -l "$recognize_language" - - -c page_separator="" | tr -d '\n' | xclip -selection clipboard elif [[ "$1" == "darkback" ]]; then # tesseract always wait colored on white images - convert - -set colorspace Gray -separate -average -negate - | tesseract -l "$recognize_language" - - -c page_separator="" | xclip -selection clipboard + convert - -set colorspace Gray -separate -average -negate - | tesseract -l "$recognize_language" - - -c page_separator="" | tr -d '\n' | xclip -selection clipboard fi notify-send -a "heyteiler" -t 1000 "heyteiler" "Recognition done!" } @@ -558,9 +558,7 @@ maimCmd () { maim_mode_options="" fi - [[ -f "${img_output}" ]] && rm "${img_output}" # rewrite file if exist - maim ${maim_mode_options} ${maim_delay} ${maim_cursor} ${img_output} - + maim ${maim_mode_options} ${maim_delay} ${maim_cursor} "${img_output}" if [[ "${1}" != "0" ]]; then notify-send -a "heyteiler" -t 1000 "heyteiler" "Chick!"; fi From 4ba675e8909a990e8d5d199a23ea8072216c5eab Mon Sep 17 00:00:00 2001 From: Denis Kalyuzhnyy Date: Sun, 31 Jan 2021 09:28:11 +0300 Subject: [PATCH 6/6] [+] dependencies comment --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 2314dc3..7fb124c 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,8 @@ Also `local` target used for openning files from history. ## Dependencies: +Choose dependencies based on necessary features: + * xclip * slop (https://github.com/naelstrof/slop) * xdg-open