├── .gitignore ├── .gitmodules ├── JSON.sh ├── .gitignore ├── .travis.yml ├── JSON.sh ├── LICENSE.APACHE2 ├── LICENSE.MIT ├── README.md ├── all-tests.sh ├── package.json └── test │ ├── invalid-test.sh │ ├── invalid │ ├── bad_unicode_sequence.json │ ├── bareword.json │ ├── bracket_key.json │ ├── colon.json │ ├── colon_obj.json │ ├── comma.json │ ├── comma_obj.json │ ├── control_char_in_string.json │ ├── decimal_point.json │ ├── empty.json │ ├── false_key.json │ ├── null_key.json │ ├── number_key.json │ ├── trailing_array_comma.json │ ├── trailing_garbage.json │ ├── trailing_object_comma.json │ ├── true_key.json │ ├── unclosed_array.json │ ├── unclosed_object.json │ ├── unclosed_string.json │ ├── weird.json │ └── weird_key.json │ ├── no-head-test.sh │ ├── parse-test.sh │ ├── solidus-test.sh │ ├── solidus │ ├── string_with_solidus.json │ ├── string_with_solidus.no-escaping.parsed │ └── string_with_solidus.with-escaping.parsed │ ├── tokenizer-test.sh │ ├── valid-test.sh │ └── valid │ ├── array.json │ ├── array.parsed │ ├── embedded.json │ ├── embedded.parsed │ ├── empty_array.json │ ├── empty_array.parsed │ ├── empty_object.json │ ├── empty_object.parsed │ ├── many_object.json │ ├── many_object.parsed │ ├── nested_array.json │ ├── nested_array.parsed │ ├── nested_object.json │ ├── nested_object.parsed │ ├── number.json │ ├── number.parsed │ ├── object.json │ ├── object.parsed │ ├── string.json │ ├── string.parsed │ ├── string_in_array.json │ ├── string_in_array.parsed │ ├── string_in_object.json │ ├── string_in_object.parsed │ ├── tab_escape.json │ └── tab_escape.parsed ├── LICENSE ├── README.md ├── bashbot.sh ├── commands.sh └── config ├── cancels.conf ├── minimums.conf ├── run.conf └── seconds.conf /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | count 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "JSON.sh"] 2 | path = JSON.sh 3 | url = http://github.com/dominictarr/JSON.sh 4 | -------------------------------------------------------------------------------- /JSON.sh/.gitignore: -------------------------------------------------------------------------------- 1 | test/errlog 2 | test/outlog 3 | 4 | # vi .swp files 5 | .*.swp 6 | -------------------------------------------------------------------------------- /JSON.sh/.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | 3 | addons: 4 | apt: 5 | packages: 6 | - bash 7 | - dash 8 | - zsh 9 | 10 | # Whatever the current shebang, replace with hardcoded shell 11 | script: > 12 | sed -i '1s@.*@#!/usr/bin/env bash@' JSON.sh && ./all-tests.sh && 13 | sed -i '1s@.*@#!/usr/bin/env zsh@' JSON.sh && ./all-tests.sh && 14 | sed -i '1s@.*@#!/usr/bin/env dash@' JSON.sh && ./all-tests.sh 15 | -------------------------------------------------------------------------------- /JSON.sh/JSON.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | throw() { 4 | echo "$*" >&2 5 | exit 1 6 | } 7 | 8 | BRIEF=0 9 | LEAFONLY=0 10 | PRUNE=0 11 | NO_HEAD=0 12 | NORMALIZE_SOLIDUS=0 13 | 14 | usage() { 15 | echo 16 | echo "Usage: JSON.sh [-b] [-l] [-p] [-s] [-h]" 17 | echo 18 | echo "-p - Prune empty. Exclude fields with empty values." 19 | echo "-l - Leaf only. Only show leaf nodes, which stops data duplication." 20 | echo "-b - Brief. Combines 'Leaf only' and 'Prune empty' options." 21 | echo "-n - No-head. Do not show nodes that have no path (lines that start with [])." 22 | echo "-s - Remove escaping of the solidus symbol (stright slash)." 23 | echo "-h - This help text." 24 | echo 25 | } 26 | 27 | parse_options() { 28 | set -- "$@" 29 | local ARGN=$# 30 | while [ "$ARGN" -ne 0 ] 31 | do 32 | case $1 in 33 | -h) usage 34 | exit 0 35 | ;; 36 | -b) BRIEF=1 37 | LEAFONLY=1 38 | PRUNE=1 39 | ;; 40 | -l) LEAFONLY=1 41 | ;; 42 | -p) PRUNE=1 43 | ;; 44 | -n) NO_HEAD=1 45 | ;; 46 | -s) NORMALIZE_SOLIDUS=1 47 | ;; 48 | ?*) echo "ERROR: Unknown option." 49 | usage 50 | exit 0 51 | ;; 52 | esac 53 | shift 1 54 | ARGN=$((ARGN-1)) 55 | done 56 | } 57 | 58 | awk_egrep () { 59 | local pattern_string=$1 60 | 61 | gawk '{ 62 | while ($0) { 63 | start=match($0, pattern); 64 | token=substr($0, start, RLENGTH); 65 | print token; 66 | $0=substr($0, start+RLENGTH); 67 | } 68 | }' pattern="$pattern_string" 69 | } 70 | 71 | tokenize () { 72 | local GREP 73 | local ESCAPE 74 | local CHAR 75 | 76 | if echo "test string" | egrep -ao --color=never "test" >/dev/null 2>&1 77 | then 78 | GREP='egrep -ao --color=never' 79 | else 80 | GREP='egrep -ao' 81 | fi 82 | 83 | if echo "test string" | egrep -o "test" >/dev/null 2>&1 84 | then 85 | ESCAPE='(\\[^u[:cntrl:]]|\\u[0-9a-fA-F]{4})' 86 | CHAR='[^[:cntrl:]"\\]' 87 | else 88 | GREP=awk_egrep 89 | ESCAPE='(\\\\[^u[:cntrl:]]|\\u[0-9a-fA-F]{4})' 90 | CHAR='[^[:cntrl:]"\\\\]' 91 | fi 92 | 93 | local STRING="\"$CHAR*($ESCAPE$CHAR*)*\"" 94 | local NUMBER='-?(0|[1-9][0-9]*)([.][0-9]*)?([eE][+-]?[0-9]*)?' 95 | local KEYWORD='null|false|true' 96 | local SPACE='[[:space:]]+' 97 | 98 | # Force zsh to expand $A into multiple words 99 | local is_wordsplit_disabled=$(unsetopt 2>/dev/null | grep -c '^shwordsplit$') 100 | if [ $is_wordsplit_disabled != 0 ]; then setopt shwordsplit; fi 101 | $GREP "$STRING|$NUMBER|$KEYWORD|$SPACE|." | egrep -v "^$SPACE$" 102 | if [ $is_wordsplit_disabled != 0 ]; then unsetopt shwordsplit; fi 103 | } 104 | 105 | parse_array () { 106 | local index=0 107 | local ary='' 108 | read -r token 109 | case "$token" in 110 | ']') ;; 111 | *) 112 | while : 113 | do 114 | parse_value "$1" "$index" 115 | index=$((index+1)) 116 | ary="$ary""$value" 117 | read -r token 118 | case "$token" in 119 | ']') break ;; 120 | ',') ary="$ary," ;; 121 | *) throw "EXPECTED , or ] GOT ${token:-EOF}" ;; 122 | esac 123 | read -r token 124 | done 125 | ;; 126 | esac 127 | [ "$BRIEF" -eq 0 ] && value=$(printf '[%s]' "$ary") || value= 128 | : 129 | } 130 | 131 | parse_object () { 132 | local key 133 | local obj='' 134 | read -r token 135 | case "$token" in 136 | '}') ;; 137 | *) 138 | while : 139 | do 140 | case "$token" in 141 | '"'*'"') key=$token ;; 142 | *) throw "EXPECTED string GOT ${token:-EOF}" ;; 143 | esac 144 | read -r token 145 | case "$token" in 146 | ':') ;; 147 | *) throw "EXPECTED : GOT ${token:-EOF}" ;; 148 | esac 149 | read -r token 150 | parse_value "$1" "$key" 151 | obj="$obj$key:$value" 152 | read -r token 153 | case "$token" in 154 | '}') break ;; 155 | ',') obj="$obj," ;; 156 | *) throw "EXPECTED , or } GOT ${token:-EOF}" ;; 157 | esac 158 | read -r token 159 | done 160 | ;; 161 | esac 162 | [ "$BRIEF" -eq 0 ] && value=$(printf '{%s}' "$obj") || value= 163 | : 164 | } 165 | 166 | parse_value () { 167 | local jpath="${1:+$1,}$2" isleaf=0 isempty=0 print=0 168 | case "$token" in 169 | '{') parse_object "$jpath" ;; 170 | '[') parse_array "$jpath" ;; 171 | # At this point, the only valid single-character tokens are digits. 172 | ''|[!0-9]) throw "EXPECTED value GOT ${token:-EOF}" ;; 173 | *) value=$token 174 | # if asked, replace solidus ("\/") in json strings with normalized value: "/" 175 | [ "$NORMALIZE_SOLIDUS" -eq 1 ] && value=$(echo "$value" | sed 's#\\/#/#g') 176 | isleaf=1 177 | [ "$value" = '""' ] && isempty=1 178 | ;; 179 | esac 180 | [ "$value" = '' ] && return 181 | [ "$NO_HEAD" -eq 1 ] && [ -z "$jpath" ] && return 182 | 183 | [ "$LEAFONLY" -eq 0 ] && [ "$PRUNE" -eq 0 ] && print=1 184 | [ "$LEAFONLY" -eq 1 ] && [ "$isleaf" -eq 1 ] && [ $PRUNE -eq 0 ] && print=1 185 | [ "$LEAFONLY" -eq 0 ] && [ "$PRUNE" -eq 1 ] && [ "$isempty" -eq 0 ] && print=1 186 | [ "$LEAFONLY" -eq 1 ] && [ "$isleaf" -eq 1 ] && \ 187 | [ $PRUNE -eq 1 ] && [ $isempty -eq 0 ] && print=1 188 | [ "$print" -eq 1 ] && printf "[%s]\t%s\n" "$jpath" "$value" 189 | : 190 | } 191 | 192 | parse () { 193 | read -r token 194 | parse_value 195 | read -r token 196 | case "$token" in 197 | '') ;; 198 | *) throw "EXPECTED EOF GOT $token" ;; 199 | esac 200 | } 201 | 202 | if ([ "$0" = "$BASH_SOURCE" ] || ! [ -n "$BASH_SOURCE" ]); 203 | then 204 | parse_options "$@" 205 | tokenize | parse 206 | fi 207 | 208 | # vi: expandtab sw=2 ts=2 209 | -------------------------------------------------------------------------------- /JSON.sh/LICENSE.APACHE2: -------------------------------------------------------------------------------- 1 | Apache License, Version 2.0 2 | 3 | Copyright (c) 2011 Dominic Tarr 4 | 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | 11 | Unless required by applicable law or agreed to in writing, software 12 | distributed under the License is distributed on an "AS IS" BASIS, 13 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | See the License for the specific language governing permissions and 15 | limitations under the License. 16 | -------------------------------------------------------------------------------- /JSON.sh/LICENSE.MIT: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2011 Dominic Tarr 4 | 5 | Permission is hereby granted, free of charge, 6 | to any person obtaining a copy of this software and 7 | associated documentation files (the "Software"), to 8 | deal in the Software without restriction, including 9 | without limitation the rights to use, copy, modify, 10 | merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom 12 | the Software is furnished to do so, 13 | subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice 16 | shall be included in all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 20 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 22 | ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | -------------------------------------------------------------------------------- /JSON.sh/README.md: -------------------------------------------------------------------------------- 1 | # JSON.sh 2 | 3 | yo, so it's a json parser written in shell, compatible with ash, bash, dash and zsh 4 | 5 | [![travis](https://secure.travis-ci.org/dominictarr/JSON.sh.png?branch=master)](https://travis-ci.org/dominictarr/JSON.sh) 6 | 7 | pipe json to it, and it traverses the json objects and prints out the 8 | path to the current object (as a JSON array) and then the object, without whitespace. 9 | 10 | ``` bash 11 | $ json_parse < package.json 12 | ["name"] "JSON.sh" 13 | ["version"] "0.0.0" 14 | ["description"] "" 15 | ["homepage"] "http://github.com/dominictarr/JSON.sh" 16 | ["repository","type"] "git" 17 | ["repository","url"] "https://github.com/dominictarr/JSON.sh.git" 18 | ["repository"] {"type":"git","url":"https://github.com/dominictarr/JSON.sh.git"} 19 | ["bin","json_parse"] "./JSON.sh" 20 | ["bin"] {"json_parse":"./JSON.sh"} 21 | ["dependencies"] {} 22 | # ... etc 23 | ``` 24 | 25 | a more complex example: 26 | 27 | ``` bash 28 | curl registry.npmjs.org/express | ./JSON.sh | egrep '\["versions","[^"]*"\]' 29 | ... try it and see 30 | ``` 31 | 32 | ## Options 33 | 34 | -b 35 | > Brief output. Combines 'Leaf only' and 'Prune empty' options. 36 | 37 | -l 38 | > Leaf only. Only show leaf nodes, which stops data duplication. 39 | 40 | -p 41 | > Prune empty. Exclude fields with empty values. 42 | 43 | -n 44 | > No-head. Don't show nodes that have no path. Normally these output a leading '[]', which you can't use in a bash array. 45 | 46 | -s 47 | > Remove escaping of the solidus symbol (stright slash). 48 | 49 | -h 50 | > Show help text. 51 | 52 | ## Cool Links 53 | 54 | * [step-/JSON.awk](https://github.com/step-/JSON.awk) JSON.sh ported to awk 55 | * [kristopolous/TickTick](https://github.com/kristopolous/TickTick) Object Oriented BASH 56 | * [archan937/jsonv.sh](https://github.com/archan937/jsonv.sh) 57 | 58 | ## Installation 59 | 60 | install via npm or from AUR on archlinux 61 | 62 | * `npm install -g JSON.sh` 63 | * `yaourt -Sy json-sh` 64 | ([json-sh on aur](https://aur.archlinux.org/packages/json-sh/) 65 | thanks to [kremlin-](https://github.com/kremlin-)) 66 | 67 | ## License 68 | 69 | This software is available under the following licenses: 70 | 71 | * MIT 72 | * Apache 2 73 | -------------------------------------------------------------------------------- /JSON.sh/all-tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd ${0%/*} 4 | 5 | #set -e 6 | fail=0 7 | tests=0 8 | #all_tests=${__dirname:} 9 | #echo PLAN ${#all_tests} 10 | for test in test/*.sh ; 11 | do 12 | tests=$((tests+1)) 13 | echo TEST: $test 14 | ./$test 15 | ret=$? 16 | if [ $ret -eq 0 ] ; then 17 | echo OK: ---- $test 18 | passed=$((passed+1)) 19 | else 20 | echo FAIL: $test $fail 21 | fail=$((fail+ret)) 22 | fi 23 | done 24 | 25 | if [ $fail -eq 0 ]; then 26 | echo -n 'SUCCESS ' 27 | exitcode=0 28 | else 29 | echo -n 'FAILURE ' 30 | exitcode=1 31 | fi 32 | echo $passed / $tests 33 | exit $exitcode 34 | -------------------------------------------------------------------------------- /JSON.sh/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "JSON.sh", 3 | "version": "0.3.2", 4 | "description": "JSON parser written in shell", 5 | "homepage": "http://github.com/dominictarr/JSON.sh", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/dominictarr/JSON.sh.git" 9 | }, 10 | "bin": { 11 | "JSON.sh": "./JSON.sh" 12 | }, 13 | "dependencies": {}, 14 | "devDependencies": {}, 15 | "author": "Dominic Tarr (http://bit.ly/dominictarr)", 16 | "scripts": { 17 | "test": "./all-tests.sh" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /JSON.sh/test/invalid-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd ${0%/*} 4 | 5 | # make test output TAP compatible 6 | # http://en.wikipedia.org/wiki/Test_Anything_Protocol 7 | 8 | fails=0 9 | tests=`ls invalid/* | wc -l` 10 | 11 | echo "1..${tests##* }" 12 | for input in invalid/* 13 | do 14 | i=$((i+1)) 15 | if ../JSON.sh < "$input" > /tmp/JSON.sh_outlog 2> /tmp/JSON.sh_errlog 16 | then 17 | echo "not ok $i - cat $input | ../JSON.sh should fail" 18 | #this should be indented with '#' at the start. 19 | echo "OUTPUT WAS >>>" 20 | cat /tmp/JSON.sh_outlog 21 | echo "<<<" 22 | fails=$((fails+1)) 23 | else 24 | echo "ok $i - $input was rejected" 25 | echo "#" `cat /tmp/JSON.sh_errlog` 26 | fi 27 | done 28 | echo "$fails test(s) failed" 29 | exit $fails 30 | -------------------------------------------------------------------------------- /JSON.sh/test/invalid/bad_unicode_sequence.json: -------------------------------------------------------------------------------- 1 | "hello\u20world" 2 | -------------------------------------------------------------------------------- /JSON.sh/test/invalid/bareword.json: -------------------------------------------------------------------------------- 1 | bareword 2 | -------------------------------------------------------------------------------- /JSON.sh/test/invalid/bracket_key.json: -------------------------------------------------------------------------------- 1 | {[: "bad"} 2 | -------------------------------------------------------------------------------- /JSON.sh/test/invalid/colon.json: -------------------------------------------------------------------------------- 1 | : 2 | -------------------------------------------------------------------------------- /JSON.sh/test/invalid/colon_obj.json: -------------------------------------------------------------------------------- 1 | { 2 | "hello": : 3 | } 4 | -------------------------------------------------------------------------------- /JSON.sh/test/invalid/comma.json: -------------------------------------------------------------------------------- 1 | [,] -------------------------------------------------------------------------------- /JSON.sh/test/invalid/comma_obj.json: -------------------------------------------------------------------------------- 1 | { 2 | "hello", "comma!" 3 | } -------------------------------------------------------------------------------- /JSON.sh/test/invalid/control_char_in_string.json: -------------------------------------------------------------------------------- 1 | "ab" 2 | -------------------------------------------------------------------------------- /JSON.sh/test/invalid/decimal_point.json: -------------------------------------------------------------------------------- 1 | . 2 | -------------------------------------------------------------------------------- /JSON.sh/test/invalid/empty.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iicc1/Check4ChangeAmazonBot/c4e438da77d4a06ca3bc80f2000652cf2120fc89/JSON.sh/test/invalid/empty.json -------------------------------------------------------------------------------- /JSON.sh/test/invalid/false_key.json: -------------------------------------------------------------------------------- 1 | {false: "bad"} 2 | -------------------------------------------------------------------------------- /JSON.sh/test/invalid/null_key.json: -------------------------------------------------------------------------------- 1 | {null: "bad"} 2 | -------------------------------------------------------------------------------- /JSON.sh/test/invalid/number_key.json: -------------------------------------------------------------------------------- 1 | {5: "bad"} 2 | -------------------------------------------------------------------------------- /JSON.sh/test/invalid/trailing_array_comma.json: -------------------------------------------------------------------------------- 1 | [1,2,3,] 2 | -------------------------------------------------------------------------------- /JSON.sh/test/invalid/trailing_garbage.json: -------------------------------------------------------------------------------- 1 | [1,2,3]' 2 | -------------------------------------------------------------------------------- /JSON.sh/test/invalid/trailing_object_comma.json: -------------------------------------------------------------------------------- 1 | {"a":1,"b":2,"c":3,} 2 | -------------------------------------------------------------------------------- /JSON.sh/test/invalid/true_key.json: -------------------------------------------------------------------------------- 1 | {true: "bad"} 2 | -------------------------------------------------------------------------------- /JSON.sh/test/invalid/unclosed_array.json: -------------------------------------------------------------------------------- 1 | [5,4,"goeu" -------------------------------------------------------------------------------- /JSON.sh/test/invalid/unclosed_object.json: -------------------------------------------------------------------------------- 1 | { 2 | "hELLO": "goodeoeu" -------------------------------------------------------------------------------- /JSON.sh/test/invalid/unclosed_string.json: -------------------------------------------------------------------------------- 1 | "Hello world 2 | -------------------------------------------------------------------------------- /JSON.sh/test/invalid/weird.json: -------------------------------------------------------------------------------- 1 | @ 2 | -------------------------------------------------------------------------------- /JSON.sh/test/invalid/weird_key.json: -------------------------------------------------------------------------------- 1 | {@: "bad"} 2 | -------------------------------------------------------------------------------- /JSON.sh/test/no-head-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd ${0%/*} 4 | tmp=${TEMP:-/tmp} 5 | tmp=${tmp%%/}/ # Avoid duplicate // 6 | 7 | fails=0 8 | i=0 9 | tests=`ls valid/*.json | wc -l` 10 | echo "1..$tests" 11 | for input in valid/*.json 12 | do 13 | input_file=${input##*/} 14 | expected="${tmp}${input_file%.json}.no-head" 15 | egrep -v '^\[]' < ${input%.json}.parsed > $expected 16 | i=$((i+1)) 17 | if ! ../JSON.sh -n < "$input" | diff -u - "$expected" 18 | then 19 | echo "not ok $i - $input" 20 | fails=$((fails+1)) 21 | else 22 | echo "ok $i - $input" 23 | fi 24 | done 25 | echo "$fails test(s) failed" 26 | exit $fails 27 | 28 | # vi: expandtab sw=2 ts=2 29 | -------------------------------------------------------------------------------- /JSON.sh/test/parse-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd ${0%/*} 4 | 5 | # Can't detect sourcing in sh, so immediately terminate the attempt to parse 6 | . ../JSON.sh /dev/null 10 | } 11 | 12 | fails=0 13 | i=0 14 | echo "1..4" 15 | for input in '"oooo" ' '[true, 1, [0, {}]] ' '{"true": 1}' 16 | do 17 | i=$((i+1)) 18 | if echo "$input" | ptest 19 | then 20 | echo "ok $i - $input" 21 | else 22 | echo "not ok $i - $input" 23 | fails=$((fails+1)) 24 | fi 25 | done 26 | 27 | if ! ptest < ../package.json 28 | then 29 | echo "not ok 4 - Parsing package.json failed!" 30 | fails=$((fails+1)) 31 | else 32 | echo "ok $i - package.json" 33 | fi 34 | 35 | echo "$fails test(s) failed" 36 | exit $fails 37 | -------------------------------------------------------------------------------- /JSON.sh/test/solidus-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd ${0%/*} 4 | 5 | INPUT=./solidus/string_with_solidus.json 6 | OUTPUT_ESCAPED=./solidus/string_with_solidus.with-escaping.parsed 7 | OUTPUT_WITHOUT_ESCAPING=./solidus/string_with_solidus.no-escaping.parsed 8 | 9 | FAILS=0 10 | 11 | echo "1..2" 12 | 13 | if ! ../JSON.sh < $INPUT| diff -u - ${OUTPUT_ESCAPED}; then 14 | echo "not ok - JSON.sh run without -s option should leave solidus escaping intact" 15 | FAILS=$((FAILS + 1)) 16 | else 17 | echo "ok $i - solidus escaping was left intact" 18 | fi 19 | 20 | if ! ../JSON.sh -s < $INPUT| diff -u - ${OUTPUT_WITHOUT_ESCAPING}; then 21 | echo "not ok - JSON.sh run with -s option should remove solidus escaping" 22 | FAILS=$((FAILS+1)) 23 | else 24 | echo "ok $i - solidus escaping has been removed" 25 | fi 26 | 27 | echo "$FAILS test(s) failed" 28 | exit $FAILS 29 | -------------------------------------------------------------------------------- /JSON.sh/test/solidus/string_with_solidus.json: -------------------------------------------------------------------------------- 1 | "http:\/\/example.com\/article\/1" 2 | -------------------------------------------------------------------------------- /JSON.sh/test/solidus/string_with_solidus.no-escaping.parsed: -------------------------------------------------------------------------------- 1 | [] "http://example.com/article/1" 2 | -------------------------------------------------------------------------------- /JSON.sh/test/solidus/string_with_solidus.with-escaping.parsed: -------------------------------------------------------------------------------- 1 | [] "http:\/\/example.com\/article\/1" 2 | -------------------------------------------------------------------------------- /JSON.sh/test/tokenizer-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd ${0%/*} 4 | 5 | # Can't detect sourcing in sh, so immediately terminate the attempt to parse 6 | . ../JSON.sh /tmp/json_ttest_expected 15 | if echo "$input" | tokenize | diff -u - /tmp/json_ttest_expected 16 | then 17 | echo "ok $i - $input" 18 | else 19 | echo "not ok $i - $input" 20 | fails=$((fails+1)) 21 | fi 22 | } 23 | 24 | ttest '"dah"' '"dah"' 25 | ttest '""' '""' 26 | ttest '["dah"]' '[' '"dah"' ']' 27 | ttest '" "' '" "' 28 | ttest '" \" "' '" \" "' 29 | 30 | ttest '["dah"]' '[' '"dah"' ']' 31 | 32 | ttest '123' '123' 33 | ttest '123.142' '123.142' 34 | ttest '-123' '-123' 35 | 36 | ttest '1e23' '1e23' 37 | ttest '0.1' '0.1' 38 | ttest '-110' '-110' 39 | ttest '-110.10' '-110.10' 40 | ttest '-110e10' '-110e10' 41 | ttest 'null' 'null' 42 | ttest 'true' 'true' 43 | ttest 'false' 'false' 44 | ttest '[ null , -110e10, "null" ]' \ 45 | '[' 'null' ',' '-110e10' ',' '"null"' ']' 46 | ttest '{"e": false}' '{' '"e"' ':' 'false' '}' 47 | ttest '{"e": "string"}' '{' '"e"' ':' '"string"' '}' 48 | 49 | if ! cat ../package.json | tokenize >/dev/null 50 | then 51 | fails=$((fails+1)) 52 | echo "Tokenizing package.json failed!" 53 | fi 54 | 55 | echo "$fails test(s) failed" 56 | exit $fails 57 | -------------------------------------------------------------------------------- /JSON.sh/test/valid-test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | cd ${0%/*} 4 | fails=0 5 | i=0 6 | tests=`ls valid/*.json | wc -l` 7 | echo "1..${tests##* }" 8 | for input in valid/*.json 9 | do 10 | expected="${input%.json}.parsed" 11 | i=$((i+1)) 12 | if ! ../JSON.sh < "$input" | diff -u - "$expected" 13 | then 14 | echo "not ok $i - $input" 15 | fails=$((fails+1)) 16 | else 17 | echo "ok $i - $input" 18 | fi 19 | done 20 | echo "$fails test(s) failed" 21 | exit $fails 22 | -------------------------------------------------------------------------------- /JSON.sh/test/valid/array.json: -------------------------------------------------------------------------------- 1 | [1,2,3,"hello"] -------------------------------------------------------------------------------- /JSON.sh/test/valid/array.parsed: -------------------------------------------------------------------------------- 1 | [0] 1 2 | [1] 2 3 | [2] 3 4 | [3] "hello" 5 | [] [1,2,3,"hello"] 6 | -------------------------------------------------------------------------------- /JSON.sh/test/valid/embedded.json: -------------------------------------------------------------------------------- 1 | {"foo": "{\"foo\":\"bar\"}"} 2 | -------------------------------------------------------------------------------- /JSON.sh/test/valid/embedded.parsed: -------------------------------------------------------------------------------- 1 | ["foo"] "{\"foo\":\"bar\"}" 2 | [] {"foo":"{\"foo\":\"bar\"}"} 3 | -------------------------------------------------------------------------------- /JSON.sh/test/valid/empty_array.json: -------------------------------------------------------------------------------- 1 | [] -------------------------------------------------------------------------------- /JSON.sh/test/valid/empty_array.parsed: -------------------------------------------------------------------------------- 1 | [] [] 2 | -------------------------------------------------------------------------------- /JSON.sh/test/valid/empty_object.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /JSON.sh/test/valid/empty_object.parsed: -------------------------------------------------------------------------------- 1 | [] {} 2 | -------------------------------------------------------------------------------- /JSON.sh/test/valid/many_object.json: -------------------------------------------------------------------------------- 1 | { 2 | "key1": "string", 3 | "key2": 3573 4 | } -------------------------------------------------------------------------------- /JSON.sh/test/valid/many_object.parsed: -------------------------------------------------------------------------------- 1 | ["key1"] "string" 2 | ["key2"] 3573 3 | [] {"key1":"string","key2":3573} 4 | -------------------------------------------------------------------------------- /JSON.sh/test/valid/nested_array.json: -------------------------------------------------------------------------------- 1 | [ 1 2 | , [] 3 | , [4, "hello", {}] 4 | , {"array": []} 5 | ] -------------------------------------------------------------------------------- /JSON.sh/test/valid/nested_array.parsed: -------------------------------------------------------------------------------- 1 | [0] 1 2 | [1] [] 3 | [2,0] 4 4 | [2,1] "hello" 5 | [2,2] {} 6 | [2] [4,"hello",{}] 7 | [3,"array"] [] 8 | [3] {"array":[]} 9 | [] [1,[],[4,"hello",{}],{"array":[]}] 10 | -------------------------------------------------------------------------------- /JSON.sh/test/valid/nested_object.json: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "key": "value", 4 | "empty": {} 5 | }, 6 | "number": 5 7 | } -------------------------------------------------------------------------------- /JSON.sh/test/valid/nested_object.parsed: -------------------------------------------------------------------------------- 1 | ["object","key"] "value" 2 | ["object","empty"] {} 3 | ["object"] {"key":"value","empty":{}} 4 | ["number"] 5 5 | [] {"object":{"key":"value","empty":{}},"number":5} 6 | -------------------------------------------------------------------------------- /JSON.sh/test/valid/number.json: -------------------------------------------------------------------------------- 1 | 3 -------------------------------------------------------------------------------- /JSON.sh/test/valid/number.parsed: -------------------------------------------------------------------------------- 1 | [] 3 2 | -------------------------------------------------------------------------------- /JSON.sh/test/valid/object.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "Value" 3 | } -------------------------------------------------------------------------------- /JSON.sh/test/valid/object.parsed: -------------------------------------------------------------------------------- 1 | ["key"] "Value" 2 | [] {"key":"Value"} 3 | -------------------------------------------------------------------------------- /JSON.sh/test/valid/string.json: -------------------------------------------------------------------------------- 1 | "hello this is a string" -------------------------------------------------------------------------------- /JSON.sh/test/valid/string.parsed: -------------------------------------------------------------------------------- 1 | [] "hello this is a string" 2 | -------------------------------------------------------------------------------- /JSON.sh/test/valid/string_in_array.json: -------------------------------------------------------------------------------- 1 | ["hello this is a string"] -------------------------------------------------------------------------------- /JSON.sh/test/valid/string_in_array.parsed: -------------------------------------------------------------------------------- 1 | [0] "hello this is a string" 2 | [] ["hello this is a string"] 3 | -------------------------------------------------------------------------------- /JSON.sh/test/valid/string_in_object.json: -------------------------------------------------------------------------------- 1 | {"key":"hello this is a string"} -------------------------------------------------------------------------------- /JSON.sh/test/valid/string_in_object.parsed: -------------------------------------------------------------------------------- 1 | ["key"] "hello this is a string" 2 | [] {"key":"hello this is a string"} 3 | -------------------------------------------------------------------------------- /JSON.sh/test/valid/tab_escape.json: -------------------------------------------------------------------------------- 1 | "hello\tworld" 2 | -------------------------------------------------------------------------------- /JSON.sh/test/valid/tab_escape.parsed: -------------------------------------------------------------------------------- 1 | [] "hello\tworld" 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Ignacio Iglesias 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Check4ChangeAmazonBot 2 | 3 | 4 | [![https://github.com/iicc1/Check4ChangeAmazonBot](https://img.shields.io/badge/Coverage-92%25-blue.svg)](https://github.com/iicc1/Check4ChangeAmazonBot) 5 | 6 | 7 | #####_Public source code for the Telegram bot_ [Check4ChangeAmazonBot](https://telegram.me/Check4ChangeAmazonBot) 8 | 9 | ============ 10 | ##### Based on __Telegram-bot-bash__: https://github.com/topkecleon/telegram-bot-bash 11 | ##### Using the official __Telegram API__: https://core.telegram.org/bots 12 | ============ 13 | 14 | ### __Information:__ 15 | (A little bit outdated, it has more functions now.) 16 | This bot tracks Amazon prices of your products all the time, this is intended to do with products that have very hight drops of price in short moments of time. Thing that usually occurs in Amazon. 17 | 18 | When a change of price is detected, it will notify you and it will write it to a prices logfile which you can access everytime you want. 19 | 20 | ============ 21 | ### __How to use the bot:__ 22 | 23 | (A little bit outdated, it has more functions now.) 24 | This bot can track up to six amazon products at the same time. Each product will be checked separately, has a different logfile and other configurations. 25 | 26 | To use the bot, you need to provide the Amazon link of the product, but the link of the offer-listing of it. For example: 27 | https://www.amazon.es/gp/offer-listing/B017T1LB2S 28 | 29 | As product checking runs separately, commands are separated for the different tracking items: 30 | 31 | `/check<1-6> ` : It will start tracking that item. 32 | 33 | `/seconds<1-6> <5-99999>` : Time between checking price of the product (default is 20s). 34 | 35 | `/cancel<1-6>` : This cancels the specified tracking. 36 | 37 | `/log<1-6>` : Bot will upload the price logfile of the tracking. 38 | 39 | - Use Notepad++ or similar to open the logfiles, otherwise the log will be shown in one line. 40 | 41 | ============ 42 | #### __Example:__ 43 | 44 | (A little bit outdated, it has more functions now.) 45 | `/check1 https://www.amazon.es/gp/offer-listing/B00P738MUU/ref=dp_olp_new?ie=UTF8&condition=new` 46 | This will asign that tracking to the _check1_ 47 | 48 | To get the log of the tracking __1__: 49 | `/log1` 50 | 51 | To set time checking (20s default): 52 | `/seconds1 40` 53 | Here we have set __40__ seconds time check for the track __1__ 54 | 55 | `/cancel1` 56 | Cancels the tracking of the track __1__ 57 | 58 | 59 | You can do this with up to 6 products, `/track2 xxxx` `/cancel4` `/seconds5 xxxx` `/log3` and so on. 60 | 61 | 62 | The number of products can't be set more high because it will overload the server and Amazon could block the IP. 63 | 64 | ============ 65 | #### __Using source code:__ 66 | 67 | To use the bot by yourself, follow this instructions: 68 | 69 | *Paste* the __TOKEN__ of your bot from @Botfather in _bashbot.sh_ 70 | 71 | *Clone the repo:* `git clone https://github.com/iicc1/Check4ChangeAmazonBot` 72 | 73 | *Start the bot:* `bash bashbot.sh start` 74 | 75 | *Stop the bot:* `bash bashbot.sh stop` 76 | 77 | ============ 78 | 79 | ##### If you have any troubles, contact me in [Telegram](https://telegram.me/iicc1) 80 | 81 | 82 | 83 | 84 | 85 | 86 | -------------------------------------------------------------------------------- /bashbot.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # bashbot, the Telegram bot written in bash. 4 | # Written by Drew (@topkecleon) and Daniil Gentili (@danogentili). 5 | # Also contributed: JuanPotato, BigNerd95, TiagoDanin, iicc1. 6 | # https://github.com/topkecleon/telegram-bot-bash 7 | 8 | # Depends on JSON.sh (http://github.com/dominictarr/JSON.sh) (MIT/Apache), 9 | # and on tmux (http://github.com/tmux/tmux) (BSD). 10 | 11 | # This file is public domain in the USA and all free countries. 12 | # Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) 13 | 14 | if [ ! -d "JSON.sh" ]; then 15 | echo "You did not clone recursively! Downloading JSON.sh..." 16 | git clone http://github.com/dominictarr/JSON.sh/ 17 | echo "JSON.sh has been downloaded. Proceeding." 18 | fi 19 | 20 | source commands.sh source 21 | URL='https://api.telegram.org/bot'$TOKEN 22 | 23 | 24 | SCRIPT="$0" 25 | MSG_URL=$URL'/sendMessage' 26 | PHO_URL=$URL'/sendPhoto' 27 | AUDIO_URL=$URL'/sendAudio' 28 | DOCUMENT_URL=$URL'/sendDocument' 29 | STICKER_URL=$URL'/sendSticker' 30 | VIDEO_URL=$URL'/sendVideo' 31 | VOICE_URL=$URL'/sendVoice' 32 | LOCATION_URL=$URL'/sendLocation' 33 | VENUE_URL=$URL'/sendVenue' 34 | ACTION_URL=$URL'/sendChatAction' 35 | FORWARD_URL=$URL'/forwardMessage' 36 | INLINE_QUERY=$URL'/answerInlineQuery' 37 | ME_URL=$URL'/getMe' 38 | ME=$(curl -s $ME_URL | ./JSON.sh/JSON.sh -s | egrep '\["result","username"\]' | cut -f 2 | cut -d '"' -f 2) 39 | 40 | 41 | FILE_URL='https://api.telegram.org/file/bot'$TOKEN'/' 42 | UPD_URL=$URL'/getUpdates?offset=' 43 | GET_URL=$URL'/getFile' 44 | OFFSET=0 45 | declare -A USER MESSAGE URLS CONTACT LOCATION 46 | 47 | send_message() { 48 | [ "$2" = "" ] && return 1 49 | local chat="$1" 50 | local text="$(echo "$2" | sed 's/ mykeyboardstartshere.*//g;s/ myfilelocationstartshere.*//g;s/ mylatstartshere.*//g;s/ mylongstartshere.*//g;s/ mytitlestartshere.*//g;s/ myaddressstartshere.*//g')" 51 | local arg="$3" 52 | [ "$3" != "safe" ] && { 53 | local keyboard="$(echo "$2" | sed '/mykeyboardstartshere /!d;s/.*mykeyboardstartshere //g;s/ myfilelocationstartshere.*//g;s/ mylatstartshere.*//g;s/ mylongstartshere.*//g;s/ mytitlestartshere.*//g;s/ myaddressstartshere.*//g')" 54 | 55 | local file="$(echo "$2" | sed '/myfilelocationstartshere /!d;s/.*myfilelocationstartshere //g;s/ mykeyboardstartshere.*//g;s/ mylatstartshere.*//g;s/ mylongstartshere.*//g;s/ mytitlestartshere.*//g;s/ myaddressstartshere.*//g')" 56 | 57 | local lat="$(echo "$2" | sed '/mylatstartshere /!d;s/.*mylatstartshere //g;s/ mykeyboardstartshere.*//g;s/ myfilelocationstartshere.*//g;s/ mylongstartshere.*//g;s/ mytitlestartshere.*//g;s/ myaddressstartshere.*//g')" 58 | 59 | local long="$(echo "$2" | sed '/mylongstartshere /!d;s/.*mylongstartshere //g;s/ mykeyboardstartshere.*//g;s/ myfilelocationstartshere.*//g;s/ mylatstartshere.*//g;s/ mytitlestartshere.*//g;s/ myaddressstartshere.*//g')" 60 | 61 | local title="$(echo "$2" | sed '/mytitlestartshere /!d;s/.*mylongstartshere //g;s/ mykeyboardstartshere.*//g;s/ myfilelocationstartshere.*//g;s/ mylatstartshere.*//g;s/ myaddressstartshere.*//g')" 62 | 63 | local address="$(echo "$2" | sed '/myaddressstartshere /!d;s/.*mylongstartshere //g;s/ mykeyboardstartshere.*//g;s/ myfilelocationstartshere.*//g;s/ mylatstartshere.*//g;s/ mytitlestartshere.*//g')" 64 | 65 | } 66 | if [ "$keyboard" != "" ]; then 67 | send_keyboard "$chat" "$text" "$keyboard" 68 | local sent=y 69 | fi 70 | if [ "$file" != "" ]; then 71 | send_file "$chat" "$file" "$text" 72 | local sent=y 73 | fi 74 | if [ "$lat" != "" -a "$long" != "" -a "$address" = "" -a "$title" = "" ]; then 75 | send_location "$chat" "$lat" "$long" 76 | local sent=y 77 | fi 78 | if [ "$lat" != "" -a "$long" != "" -a "$address" != "" -a "$title" != "" ]; then 79 | send_venue "$chat" "$lat" "$long" "$title" "$address" 80 | local sent=y 81 | fi 82 | if [ "$sent" != "y" ];then 83 | send_text "$chat" "$text" 84 | fi 85 | 86 | } 87 | 88 | send_text() { 89 | case "$2" in 90 | html_parse_mode*) 91 | send_html_message "$1" "${2//html_parse_mode}" 92 | ;; 93 | markdown_parse_mode*) 94 | send_markdown_message "$1" "${2//markdown_parse_mode}" 95 | ;; 96 | *) 97 | res=$(curl -s "$MSG_URL" -d "chat_id=$1" -d "text=$2") 98 | ;; 99 | esac 100 | } 101 | 102 | send_markdown_message() { 103 | res=$(curl -s "$MSG_URL" -d "chat_id=$1" -d "text=$2" -d "parse_mode=markdown") 104 | } 105 | 106 | send_html_message() { 107 | res=$(curl -s "$MSG_URL" -F "chat_id=$1" -F "text=$2" -F "parse_mode=html") 108 | } 109 | 110 | answer_inline_query() { 111 | case $2 in 112 | "article") 113 | InlineQueryResult='[{"type":"'$2'","id":"$RANDOM","title":"'$3'","message_text":"'$4'"}]' 114 | ;; 115 | "photo") 116 | InlineQueryResult='[{"type":"'$2'","id":"$RANDOM","photo_url":"'$3'","thumb_url":"'$4'"}]' 117 | ;; 118 | "gif") 119 | InlineQueryResult='[{"type":"'$2'","id":"$RANDOM","gif_url":"'$3'"}]' 120 | ;; 121 | "mpeg4_gif") 122 | InlineQueryResult='[{"type":"'$2'","id":"$RANDOM","mpeg4_url":"'$3'"}]' 123 | ;; 124 | "video") 125 | InlineQueryResult='[{"type":"'$2'","id":"$RANDOM","video_url":"'$3'","mime_type":"'$4'","thumb_url":"'$5'","title":"'$6'"}]' 126 | ;; 127 | "audio") 128 | InlineQueryResult='[{"type":"'$2'","id":"$RANDOM","audio_url":"'$3'","title":"'$4'"}]' 129 | ;; 130 | "voice") 131 | InlineQueryResult='[{"type":"'$2'","id":"$RANDOM","voice_url":"'$3'","title":"'$4'"}]' 132 | ;; 133 | "document") 134 | InlineQueryResult='[{"type":"'$2'","id":"$RANDOM","title":"'$3'","caption":"'$4'","document_url":"'$5'","mime_type":"'$6'"}]' 135 | ;; 136 | "location") 137 | InlineQueryResult='[{"type":"'$2'","id":"$RANDOM","latitude":"'$3'","longitude":"'$4'","title":"'$5'"}]' 138 | ;; 139 | "venue") 140 | InlineQueryResult='[{"type":"'$2'","id":"$RANDOM","latitude":"'$3'","longitude":"'$4'","title":"'$5'","address":"'$6'"}]' 141 | ;; 142 | "contact") 143 | InlineQueryResult='[{"type":"'$2'","id":"$RANDOM","phone_number":"'$3'","first_name":"'$4'"}]' 144 | ;; 145 | 146 | # Cached media stored in Telegram server 147 | 148 | "cached_photo") 149 | InlineQueryResult='[{"type":"photo","id":"$RANDOM","photo_file_id":"'$3'"}]' 150 | ;; 151 | "cached_gif") 152 | InlineQueryResult='[{"type":"gif","id":"$RANDOM","gif_file_id":"'$3'"}]' 153 | ;; 154 | "cached_mpeg4_gif") 155 | InlineQueryResult='[{"type":"mpeg4_gif","id":"$RANDOM","mpeg4_file_id":"'$3'"}]' 156 | ;; 157 | "cached_sticker") 158 | InlineQueryResult='[{"type":"sticker","id":"$RANDOM","sticker_file_id":"'$3'"}]' 159 | ;; 160 | "cached_document") 161 | InlineQueryResult='[{"type":"document","id":"$RANDOM","title":"'$3'","document_file_id":"'$4'"}]' 162 | ;; 163 | "cached_video") 164 | InlineQueryResult='[{"type":"video","id":"$RANDOM","video_file_id":"'$3'","title":"'$4'"}]' 165 | ;; 166 | "cached_voice") 167 | InlineQueryResult='[{"type":"voice","id":"$RANDOM","voice_file_id":"'$3'","title":"'$4'"}]' 168 | ;; 169 | "cached_audio") 170 | InlineQueryResult='[{"type":"audio","id":"$RANDOM","audio_file_id":"'$3'"}]' 171 | ;; 172 | 173 | esac 174 | 175 | res=$(curl -s "$INLINE_QUERY" -F "inline_query_id=$1" -F "results=$InlineQueryResult") 176 | 177 | } 178 | 179 | send_keyboard() { 180 | local chat="$1" 181 | local text="$2" 182 | shift 2 183 | local keyboard=init 184 | OLDIFS=$IFS 185 | IFS=$(echo -en "\"") 186 | for f in $*;do [ "$f" != " " ] && local keyboard="$keyboard, [\"$f\"]";done 187 | IFS=$OLDIFS 188 | local keyboard=${keyboard/init, /} 189 | res=$(curl -s "$MSG_URL" --header "content-type: multipart/form-data" -F "chat_id=$chat" -F "text=$text" -F "reply_markup={\"keyboard\": [$keyboard],\"one_time_keyboard\": true}") 190 | } 191 | 192 | get_file() { 193 | [ "$1" != "" ] && echo $FILE_URL$(curl -s "$GET_URL" -F "file_id=$1" | ./JSON.sh/JSON.sh -s | egrep '\["result","file_path"\]' | cut -f 2 | cut -d '"' -f 2) 194 | } 195 | 196 | send_file() { 197 | [ "$2" = "" ] && return 198 | local chat_id=$1 199 | local file=$2 200 | #echo "$file" | grep -qE $FILE_REGEX || return 201 | local ext="${file##*.}" 202 | case $ext in 203 | "mp3") 204 | CUR_URL=$AUDIO_URL 205 | WHAT=audio 206 | STATUS=upload_audio 207 | ;; 208 | png|jpg|jpeg|gif) 209 | CUR_URL=$PHO_URL 210 | WHAT=photo 211 | STATUS=upload_photo 212 | ;; 213 | webp) 214 | CUR_URL=$STICKER_URL 215 | WHAT=sticker 216 | STATUS= 217 | ;; 218 | mp4) 219 | CUR_URL=$VIDEO_URL 220 | WHAT=video 221 | STATUS=upload_video 222 | ;; 223 | 224 | ogg) 225 | CUR_URL=$VOICE_URL 226 | WHAT=voice 227 | STATUS= 228 | ;; 229 | *) 230 | CUR_URL=$DOCUMENT_URL 231 | WHAT=document 232 | STATUS=upload_document 233 | ;; 234 | esac 235 | send_action $chat_id $STATUS 236 | res=$(curl -s "$CUR_URL" -F "chat_id=$chat_id" -F "$WHAT=@$file" -F "caption=$3") 237 | } 238 | 239 | # typing for text messages, upload_photo for photos, record_video or upload_video for videos, record_audio or upload_audio for audio files, upload_document for general files, find_location for location 240 | 241 | send_action() { 242 | [ "$2" = "" ] && return 243 | res=$(curl -s "$ACTION_URL" -F "chat_id=$1" -F "action=$2") 244 | } 245 | 246 | send_location() { 247 | [ "$3" = "" ] && return 248 | res=$(curl -s "$LOCATION_URL" -F "chat_id=$1" -F "latitude=$2" -F "longitude=$3") 249 | } 250 | 251 | send_venue() { 252 | [ "$5" = "" ] && return 253 | [ "$6" != "" ] add="-F \"foursquare_id=$6\"" 254 | res=$(curl -s "$VENUE_URL" -F "chat_id=$1" -F "latitude=$2" -F "longitude=$3" -F "title=$4" -F "address=$5" $add) 255 | } 256 | 257 | 258 | forward() { 259 | [ "$3" = "" ] && return 260 | res=$(curl -s "$FORWARD_URL" -F "chat_id=$1" -F "from_chat_id=$2" -F "message_id=$3") 261 | } 262 | 263 | startproc() { 264 | killproc 265 | mkfifo /tmp/$copname 266 | TMUX= tmux new-session -d -s $copname "$* &>/tmp/$copname; echo imprettydarnsuredatdisisdaendofdacmd>/tmp/$copname" 267 | TMUX= tmux new-session -d -s sendprocess_$copname "bash $SCRIPT outproc ${USER[ID]} $copname" 268 | } 269 | 270 | killproc() { 271 | (tmux kill-session -t $copname; echo imprettydarnsuredatdisisdaendofdacmd>/tmp/$copname; tmux kill-session -t sendprocess_$copname; rm -r /tmp/$copname)2>/dev/null 272 | } 273 | 274 | inproc() { 275 | tmux send-keys -t $copname "$MESSAGE ${URLS[*]} 276 | " 277 | } 278 | 279 | process_client() { 280 | # Message 281 | MESSAGE=$(echo "$res" | egrep '\["result",0,"message","text"\]' | cut -f 2 | cut -d '"' -f 2) 282 | 283 | # User 284 | USER[ID]=$(echo "$res" | egrep '\["result",0,"message","chat","id"\]' | cut -f 2) 285 | USER[FIRST_NAME]=$(echo "$res" | egrep '\["result",0,"message","chat","first_name"\]' | cut -f 2 | cut -d '"' -f 2) 286 | USER[LAST_NAME]=$(echo "$res" | egrep '\["result",0,"message","chat","last_name"\]' | cut -f 2 | cut -d '"' -f 2) 287 | USER[USERNAME]=$(echo "$res" | egrep '\["result",0,"message","chat","username"\]' | cut -f 2 | cut -d '"' -f 2) 288 | 289 | # Audio 290 | URLS[AUDIO]=$(get_file $(echo "$res" | egrep '\["result",0,"message","audio","file_id"\]' | cut -f 2 | cut -d '"' -f 2)) 291 | # Document 292 | URLS[DOCUMENT]=$(get_file $(echo "$res" | egrep '\["result",0,"message","document","file_id"\]' | cut -f 2 | cut -d '"' -f 2)) 293 | # Photo 294 | URLS[PHOTO]=$(get_file $(echo "$res" | egrep '\["result",0,"message","photo",.*,"file_id"\]' | cut -f 2 | cut -d '"' -f 2 | sed -n '$p')) 295 | # Sticker 296 | URLS[STICKER]=$(get_file $(echo "$res" | egrep '\["result",0,"message","sticker","file_id"\]' | cut -f 2 | cut -d '"' -f 2)) 297 | # Video 298 | URLS[VIDEO]=$(get_file $(echo "$res" | egrep '\["result",0,"message","video","file_id"\]' | cut -f 2 | cut -d '"' -f 2)) 299 | # Voice 300 | URLS[VOICE]=$(get_file $(echo "$res" | egrep '\["result",0,"message","voice","file_id"\]' | cut -f 2 | cut -d '"' -f 2)) 301 | 302 | # Contact 303 | CONTACT[NUMBER]=$(echo "$res" | egrep '\["result",0,"message","contact","phone_number"\]' | cut -f 2 | cut -d '"' -f 2) 304 | CONTACT[FIRST_NAME]=$(echo "$res" | egrep '\["result",0,"message","contact","first_name"\]' | cut -f 2 | cut -d '"' -f 2) 305 | CONTACT[LAST_NAME]=$(echo "$res" | egrep '\["result",0,"message","contact","last_name"\]' | cut -f 2 | cut -d '"' -f 2) 306 | CONTACT[USER_ID]=$(echo "$res" | egrep '\["result",0,"message","contact","user_id"\]' | cut -f 2 | cut -d '"' -f 2) 307 | 308 | # Caption 309 | CAPTION=$(echo "$res" | egrep '\["result",0,"message","caption"\]' | cut -f 2 | cut -d '"' -f 2) 310 | 311 | # Location 312 | LOCATION[LONGITUDE]=$(echo "$res" | egrep '\["result",0,"message","location","longitude"\]' | cut -f 2 | cut -d '"' -f 2) 313 | LOCATION[LATITUDE]=$(echo "$res" | egrep '\["result",0,"message","location","latitude"\]' | cut -f 2 | cut -d '"' -f 2) 314 | NAME="$(basename ${URLS[*]} &>/dev/null)" 315 | 316 | # Tmux 317 | copname="$ME"_"${USER[ID]}" 318 | 319 | source commands.sh 320 | 321 | tmpcount="COUNT${USER[ID]}" 322 | cat count | grep -q "$tmpcount" || echo "$tmpcount">>count 323 | # To get user count execute bash bashbot.sh count 324 | } 325 | 326 | # source the script with source as param to use functions in other scripts 327 | while [ "$1" == "startbot" ]; do { 328 | 329 | res=$(curl -s $UPD_URL$OFFSET | ./JSON.sh/JSON.sh -s) 330 | 331 | # Offset 332 | OFFSET=$(echo "$res" | egrep '\["result",0,"update_id"\]' | cut -f 2) 333 | OFFSET=$((OFFSET+1)) 334 | 335 | if [ $OFFSET != 1 ]; then 336 | process_client& 337 | fi 338 | 339 | }; done 340 | 341 | 342 | case "$1" in 343 | "outproc") 344 | until [ "$line" = "imprettydarnsuredatdisisdaendofdacmd" ];do 345 | line= 346 | read -t 10 line 347 | [ "$line" != "" -a "$line" != "imprettydarnsuredatdisisdaendofdacmd" ] && send_message "$2" "$line" 348 | done /dev/null 362 | tmux new-session -d -s $ME "bash $SCRIPT startbot" && echo "Bot started successfully. Tmux session name is $ME" || echo "An error occurred while starting the bot." 363 | ;; 364 | "kill") 365 | tmux kill-session -t $ME &>/dev/null 366 | echo "Bot was killed successfully. " 367 | ;; 368 | "help") 369 | less README.md 370 | ;; 371 | "attach") 372 | tmux attach -t $ME 373 | ;; 374 | *) 375 | echo "Available arguments: outproc, count, broadcast, start, kill, help, attach" 376 | ;; 377 | esac 378 | -------------------------------------------------------------------------------- /commands.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Edit your commands in this file. 3 | 4 | # This file is public domain in the USA and all free countries. 5 | # Elsewhere, consider it to be WTFPLv2. (wtfpl.net/txt/copying) 6 | 7 | if [ "$1" = "source" ];then 8 | # Edit the token in here 9 | TOKEN='Put your token here!' 10 | # Set INLINE to 1 in order to receive inline queries. 11 | # To enable this option in your bot, send the /setinline command to @BotFather. 12 | INLINE=0 13 | # Set to .* to allow sending files from all locations 14 | #FILE_REGEX='/home/user/allowed/.*' 15 | fi 16 | 17 | 18 | #============================================================================================== 19 | #============================================================================================== 20 | #============================================================================================== 21 | 22 | # if [ -z "${USER[USERNAME]}" ], then 23 | # USER[USERNAME]=(USER[FIRST_NAME]) 24 | # fi 25 | 26 | ID=${USER[ID]} 27 | LOG1=files/1_${ID}.log 28 | LOG2=files/2_${ID}.log 29 | LOG3=files/3_${ID}.log 30 | LOG4=files/4_${ID}.log 31 | LOG5=files/5_${ID}.log 32 | LOG6=files/6_${ID}.log 33 | 34 | #ls | grep $ID 35 | #if [ $? != 0 ]; then 36 | # touch $LOG1 37 | # touch $LOG2 38 | # touch $LOG3 39 | # touch $LOG4 40 | # touch $LOG5 41 | # touch $LOG6 42 | # fi 43 | 44 | RUN=config/run.conf 45 | CANCEL=config/cancels.conf 46 | FSEC=config/seconds.conf 47 | FMIN=config/minimums.conf 48 | SEC=20 49 | 50 | 51 | # ######### # 52 | # FUNCTIONS # 53 | # ######### # 54 | 55 | check_settings () { 56 | 57 | # 1 58 | 59 | RUN1=$(grep ${ID}_1 $RUN ) 60 | if [ $? == 1 ]; then 61 | RUN1=$(echo "Not running" ) 62 | else 63 | RUN1=$(echo "Running" ) 64 | fi 65 | 66 | SEC1=$(grep ${ID}_1 $FSEC | cut -d '_' -f3 ) 67 | if [ -z "${SEC1}" ]; then 68 | SEC1=20 69 | fi 70 | 71 | PRICE1=$(grep ${ID}_1 $FMIN | cut -d '_' -f3 ) 72 | if [ -z "${PRICE1}" ]; then 73 | PRICE1=$(echo "When price changes" ) 74 | else 75 | PRICE1=$(echo "If drops under ${PRICE1}EUR/GBP" ) 76 | fi 77 | LINK1=$(cat $LOG1 | head -1 ) 78 | 79 | # 2 80 | 81 | RUN2=$(grep ${ID}_2 $RUN ) 82 | if [ $? == 1 ]; then 83 | RUN2=$(echo "Not running" ) 84 | else 85 | RUN2=$(echo "Running" ) 86 | fi 87 | 88 | SEC2=$(grep ${ID}_2 $FSEC | cut -d '_' -f3 ) 89 | if [ -z "${SEC2}" ]; then 90 | SEC2=20 91 | fi 92 | 93 | PRICE2=$(grep ${ID}_2 $FMIN | cut -d '_' -f3 ) 94 | if [ -z "${PRICE2}" ]; then 95 | PRICE2=$(echo "When price changes" ) 96 | else 97 | PRICE2=$(echo "If drops under ${PRICE2}EUR/GBP" ) 98 | fi 99 | 100 | LINK2=$(cat $LOG2 | head -1 ) 101 | 102 | # 3 103 | 104 | RUN3=$(grep ${ID}_3 $RUN ) 105 | if [ $? == 1 ]; then 106 | RUN3=$(echo "Not running" ) 107 | else 108 | RUN3=$(echo "Running" ) 109 | fi 110 | 111 | SEC3=$(grep ${ID}_3 $FSEC | cut -d '_' -f3 ) 112 | if [ -z "${SEC3}" ]; then 113 | SEC3=20 114 | fi 115 | 116 | PRICE3=$(grep ${ID}_3 $FMIN | cut -d '_' -f3 ) 117 | if [ -z "${PRICE3}" ]; then 118 | PRICE3=$(echo "When price changes" ) 119 | else 120 | PRICE3=$(echo "If drops under ${PRICE3}EUR/GBP" ) 121 | fi 122 | 123 | LINK3=$(cat $LOG3 | head -1 ) 124 | 125 | # 4 126 | 127 | RUN4=$(grep ${ID}_4 $RUN ) 128 | if [ $? == 1 ]; then 129 | RUN4=$(echo "Not running" ) 130 | else 131 | RUN4=$(echo "Running" ) 132 | fi 133 | 134 | SEC4=$(grep ${ID}_4 $FSEC | cut -d '_' -f3 ) 135 | if [ -z "${SEC4}" ]; then 136 | SEC4=20 137 | fi 138 | 139 | PRICE4=$(grep ${ID}_4 $FMIN | cut -d '_' -f3 ) 140 | if [ -z "${PRICE4}" ]; then 141 | PRICE4=$(echo "When price changes" ) 142 | else 143 | PRICE4=$(echo "If drops under ${PRICE4}EUR/GBP" ) 144 | fi 145 | 146 | LINK4=$(cat $LOG4 | head -1 ) 147 | 148 | # 5 149 | 150 | RUN5=$(grep ${ID}_5 $RUN ) 151 | if [ $? == 1 ]; then 152 | RUN5=$(echo "Not running" ) 153 | else 154 | RUN5=$(echo "Running" ) 155 | fi 156 | 157 | SEC5=$(grep ${ID}_5 $FSEC | cut -d '_' -f3 ) 158 | if [ -z "${SEC5}" ]; then 159 | SEC5=20 160 | fi 161 | 162 | PRICE5=$(grep ${ID}_5 $FMIN | cut -d '_' -f3 ) 163 | if [ -z "${PRICE5}" ]; then 164 | PRICE5=$(echo "When price changes" ) 165 | else 166 | PRICE5=$(echo "If drops under ${PRICE5}EUR/GBP" ) 167 | fi 168 | 169 | LINK5=$(cat $LOG5 | head -1 ) 170 | 171 | # 6 172 | 173 | RUN6=$(grep ${ID}_6 $RUN ) 174 | if [ $? == 1 ]; then 175 | RUN6=$(echo "Not running" ) 176 | else 177 | RUN6=$(echo "Running" ) 178 | fi 179 | 180 | SEC6=$(grep ${ID}_6 $FSEC | cut -d '_' -f3 ) 181 | if [ -z "${SEC6}" ]; then 182 | SEC6=20 183 | fi 184 | 185 | PRICE6=$(grep ${ID}_6 $FMIN | cut -d '_' -f3 ) 186 | if [ -z "${PRICE6}" ]; then 187 | PRICE6=$(echo "When price changes" ) 188 | else 189 | PRICE6=$(echo "If drops under ${PRICE6}EUR/GBP" ) 190 | fi 191 | 192 | LINK6=$(cat $LOG6 | head -1 ) 193 | 194 | send_markdown_message "$ID" "*Current settings:* 195 | 196 | *Track 1:* 197 | _State:_ $RUN1 198 | _Checking Time:_ ${SEC1}s 199 | _Price Alert:_ ${PRICE1} 200 | $LINK1 201 | *Track 2:* 202 | _State:_ $RUN2 203 | _Checking Time:_ ${SEC2}s 204 | _Price Alert:_ ${PRICE2} 205 | $LINK2 206 | *Track 3:* 207 | _State:_ $RUN3 208 | _Checking Time:_ ${SEC3}s 209 | _Price Alert:_ ${PRICE3} 210 | $LINK3 211 | *Track 4:* 212 | _State:_ $RUN4 213 | _Checking Time:_ ${SEC4}s 214 | _Price Alert:_ ${PRICE4} 215 | $LINK4 216 | *Track 5:* 217 | _State:_ $RUN5 218 | _Checking Time:_ ${SEC5}s 219 | _Price Alert:_ ${PRICE5} 220 | $LINK5 221 | *Track 6:* 222 | _State:_ $RUN6 223 | _Checking Time:_ ${SEC6}s 224 | _Price Alert:_ ${PRICE6} 225 | $LINK6 226 | " 227 | 228 | } 229 | 230 | cancel_check () { 231 | 232 | send_markdown_message "$ID" "*Tracking $1 stopped*" 233 | echo ${ID}_${1} >> $CANCEL 234 | grep -v ${ID}_${1} $RUN > $RUN.bak 235 | mv $RUN.bak $RUN 236 | 237 | grep -v ${ID}_${1} $FSEC > $FSEC.bak 238 | mv $FSEC.bak $FSEC 239 | 240 | grep -v ${ID}_${1} $FMIN > $FMIN.bak 241 | mv $FMIN.bak $FMIN 242 | 243 | rm files/${1}_${ID}.log 244 | 245 | exit 1 246 | } 247 | 248 | send_log () { 249 | 250 | send_markdown_message "$ID" "*Sending log for Track ${1}*" 251 | send_action "$ID" "upload_document" 252 | send_file "$ID" "files/${1}_${ID}.log" "Check4ChangeAmazonBot Price Log${1}" 253 | 254 | } 255 | 256 | seconds_check () { 257 | 258 | TIME=`echo $MESSAGE | cut -d ' ' -f2` 259 | if [ -z "${TIME}" ]; then 260 | send_message "$ID" "Please, send a correct time." 261 | exit 0 262 | fi 263 | 264 | if [[ $TIME == *['!'@#\$%^\&*()_+a-zA-Z]* ]]; then 265 | send_message "$ID" "Please, send a correct time." 266 | exit 0 267 | fi 268 | 269 | if [ "$TIME" -gt 9999 ] || [ "$TIME" -le 4 ] ; then 270 | send_message "$ID" "Time check invalid." 271 | exit 0 272 | fi 273 | 274 | grep -v "${ID}_${1}_" $FSEC > $FSEC.bak 275 | mv $FSEC.bak $FSEC 276 | echo ${ID}_${1}_${TIME} >> $FSEC 277 | send_markdown_message "$ID" "Time check for product* $1 *set to* ${TIME}*." 278 | } 279 | 280 | 281 | min_check () { 282 | 283 | MIN=`echo $MESSAGE | cut -d ' ' -f2` 284 | if [ -z "${MIN}" ]; then 285 | send_message "$ID" "Please, send a correct minimum price." 286 | exit 0 287 | fi 288 | 289 | if [[ $MIN == *['!'@#\$%^\&*()_+a-zA-Z]* ]]; then 290 | send_message "$ID" "Please, send a correct minimum price." 291 | exit 0 292 | fi 293 | 294 | if [ "$MIN" -gt 99999 ] || [ "$MIN" -le 1 ] ; then 295 | send_message "$ID" "Minimum price invalid." 296 | exit 0 297 | fi 298 | 299 | grep -v "${ID}_${1}_" $FMIN > $FMIN.bak 300 | mv $FMIN.bak $FMIN 301 | echo ${ID}_${1}_${MIN} >> $FMIN 302 | send_markdown_message "$ID" "Minimum price for product* $1 *set to* ${MIN}EUR/GBP*." 303 | } 304 | 305 | 306 | 307 | check_link () { 308 | 309 | SPECIAL=0 310 | BADGE='EUR' 311 | SEC=20 312 | MIN=0 313 | LOG=files/${1}_${ID}.log 314 | 315 | grep -v $ID_$1 $CANCEL > $CANCEL.bak 316 | mv $CANCEL.bak $CANCEL 317 | ASIN=`echo $MESSAGE | cut -d ' ' -f2` 318 | COUNTRY=`echo $MESSAGE | cut -d ' ' -f3` 319 | 320 | grep -e "${ID}_${1}" $RUN 321 | if [ $? == 0 ]; then 322 | send_message "$ID" "Please, cancel the tracking before starting a new one. 323 | Write: /cancel$1" 324 | break 325 | fi 326 | 327 | if [ -z "${ASIN}" ]; then 328 | send_message "$ID" "Please, send the ASIN correctly." 329 | break 330 | fi 331 | 332 | echo $ASIN | grep -e "B0" 333 | if [ $? != 0 ]; then 334 | send_markdown_message "$ID" "Please, send the *ASIN* of the product with the country name, like this: /check1 B017T1LB2S ES" 335 | break 336 | fi 337 | 338 | if [ -z "${COUNTRY}" ]; then 339 | send_message "$ID" "Please, send the country code (ES UK DE FR IT) correctly, like this: /check1 B017T1LB2S ES" 340 | break 341 | fi 342 | 343 | if [ "$COUNTRY" = "ES" ] || [ "$COUNTRY" = "IT" ] || [ "$COUNTRY" = "DE" ] || [ "$COUNTRY" = "UK" ] || [ "$COUNTRY" = "FR" ]; then 344 | 345 | if [ "$COUNTRY" = "ES" ]; then 346 | LOCALE=es 347 | BADGE='EUR' 348 | fi 349 | 350 | if [ "$COUNTRY" = "IT" ]; then 351 | LOCALE=it 352 | BADGE='EUR' 353 | fi 354 | 355 | if [ "$COUNTRY" = "DE" ]; then 356 | LOCALE=de 357 | BADGE='EUR' 358 | fi 359 | 360 | if [ "$COUNTRY" = "UK" ]; then 361 | LOCALE=co.uk 362 | SPECIAL=1 363 | BADGE='GBP' 364 | fi 365 | 366 | if [ "$COUNTRY" = "FR" ]; then 367 | LOCALE=fr 368 | BADGE='EUR' 369 | fi 370 | 371 | else 372 | send_message "$ID" "Please, send the country code (ES UK DE FR IT) correctly, like this: /check1 B017T1LB2S ES" 373 | break 374 | 375 | fi 376 | 377 | LINK=https://www.amazon.${LOCALE}/gp/offer-listing/${ASIN} 378 | 379 | send_markdown_message "$ID" "*Tracking link:* *$LINK*" 380 | RELX=0 381 | 382 | rm ${LOG} 383 | echo "_Link:_ ${LINK}" >> $LOG 384 | echo " " >> ${LOG} 385 | echo "telegram.me/Check4ChangeAmazonBot" >> ${LOG} 386 | echo " " >> ${LOG} 387 | echo "---- START MONITORING LOG ----" >> ${LOG} 388 | 389 | 390 | grep -e "${ID}_${1}_" $FSEC 391 | if [ $? == 0 ]; then 392 | SEC=$(grep -e "${ID}_${1}_" $FSEC | cut -d "_" -f 3 | head -1 ) 393 | fi 394 | 395 | grep -e "${ID}_${1}_" $FMIN 396 | if [ $? == 0 ]; then 397 | MIN=$(grep -e "${ID}_${1}_" $FMIN | cut -d "_" -f 3 | head -1 ) 398 | else 399 | MIN=0 400 | fi 401 | 402 | echo "${ID}_${1}" >> $RUN 403 | 404 | while true; do 405 | 406 | # If price changes when running. Temporal solution. 407 | grep -e "${ID}_${1}_" $FSEC 408 | if [ $? == 0 ]; then 409 | SEC=$(grep -e "${ID}_${1}_" $FSEC | cut -d "_" -f 3 | head -1 ) 410 | fi 411 | 412 | grep -e "${ID}_${1}_" $FMIN 413 | if [ $? == 0 ]; then 414 | MIN=$(grep -e "${ID}_${1}_" $FMIN | cut -d "_" -f 3 | head -1 ) 415 | else 416 | MIN=0 417 | fi 418 | 419 | grep -e $ID_$1 $CANCEL 420 | if [ $? == 0 ]; then 421 | break 422 | exit 423 | fi 424 | 425 | date=$(date) 426 | 427 | if [ "$SPECIAL" == "1" ]; then 428 | REL=`curl -s $LINK | grep '' | head -1 | cut -d ">" -f 2 | cut -d "<" -f1 | sed 's/^[[:space:]]*//' | cut -c3- | cut -f 1 -d" "` 429 | 430 | else 431 | REL=`curl -s $LINK | grep '' | head -1 | cut -d ">" -f 2 | cut -d "<" -f1 | sed 's/^[[:space:]]*//' | cut -f 2 -d" " | tr "," "."` 432 | 433 | fi 434 | 435 | if [ -z "$REL" ]; then 436 | sleep 2 437 | continue 438 | fi 439 | 440 | 441 | if [ "$REL" != "$RELX" ]; then 442 | if [ "$RELX" == "0" ]; then 443 | send_markdown_message "$ID" "*Current price:* $REL $BADGE" 444 | send_markdown_message "$ID" "*Checking time:* $SEC seconds" 445 | send_markdown_message "$ID" "*Running!*" 446 | echo "$REL ------- $date" >> ${LOG} 447 | RELX=$REL 448 | continue 449 | fi 450 | 451 | 452 | if [ "$MIN" == "0" ]; then 453 | send_markdown_message "$ID" "*Price for Track $1 has changed!* 454 | _Old price:_ $RELX $BADGE 455 | _New price:_ $REL $BADGE 456 | $LINK" 457 | else 458 | MATCH=$( echo "$MIN>$REL" | bc ) 459 | if [ $MATCH -eq 1 ]; then 460 | 461 | send_markdown_message "$ID" "*Price for Track $1 has changed!* 462 | _Alert price:_ $MIN $BADGE 463 | _New price:_ $REL $BADGE 464 | $LINK" 465 | fi 466 | fi 467 | 468 | 469 | 470 | echo "$REL ------- $date" >> ${LOG} 471 | 472 | 473 | fi 474 | sleep $SEC 475 | RELX=$REL 476 | 477 | done 478 | } 479 | 480 | echo $MESSAGE | grep "^/check" 481 | if [ $? == 0 ]; then 482 | CHECK=`echo $MESSAGE | cut -d ' ' -f1` 483 | if [ $CHECK == "/check1" ]; then 484 | check_link "1" 485 | elif [ $CHECK == "/check2" ]; then 486 | check_link "2" 487 | elif [ $CHECK == "/check3" ]; then 488 | check_link "3" 489 | elif [ $CHECK == "/check4" ]; then 490 | check_link "4" 491 | elif [ $CHECK == "/check5" ]; then 492 | check_link "5" 493 | elif [ $CHECK == "/check6" ]; then 494 | check_link "6" 495 | fi 496 | fi 497 | 498 | echo $MESSAGE | grep "^/seconds" 499 | if [ $? == 0 ]; then 500 | CHECK=`echo $MESSAGE | cut -d ' ' -f1` 501 | if [ $CHECK == "/seconds1" ]; then 502 | seconds_check "1" 503 | elif [ $CHECK == "/seconds2" ]; then 504 | seconds_check "2" 505 | elif [ $CHECK == "/seconds3" ]; then 506 | seconds_check "3" 507 | elif [ $CHECK == "/seconds4" ]; then 508 | seconds_check "4" 509 | elif [ $CHECK == "/seconds5" ]; then 510 | seconds_check "5" 511 | elif [ $CHECK == "/seconds6" ]; then 512 | seconds_check "6" 513 | fi 514 | fi 515 | 516 | echo $MESSAGE | grep "^/price" 517 | if [ $? == 0 ]; then 518 | CHECK=`echo $MESSAGE | cut -d ' ' -f1` 519 | if [ $CHECK == "/price1" ]; then 520 | min_check "1" 521 | elif [ $CHECK == "/price2" ]; then 522 | min_check "2" 523 | elif [ $CHECK == "/price3" ]; then 524 | min_check "3" 525 | elif [ $CHECK == "/price4" ]; then 526 | min_check "4" 527 | elif [ $CHECK == "/price5" ]; then 528 | min_check "5" 529 | elif [ $CHECK == "/price6" ]; then 530 | min_check "6" 531 | fi 532 | fi 533 | 534 | case $MESSAGE in 535 | 536 | '/help') 537 | send_action "${USER[ID]}" "typing" 538 | send_markdown_message "${USER[ID]}" "*How to use the bot:* 539 | 540 | This bot can track up to *six* Amazon products at the same time. Each product will be checked separately, has a different logfile and other configurations. 541 | 542 | To use the bot, you need to provide the Amazon *ASIN* of the product wich can be taken from the link of the product. 543 | For example, for this product: _https://www.amazon.es/dp/B013P2K9NC_ the *ASIN* is B013P2K9NC. 544 | If you don't know how to take the ASIN of the product, send the Amazon link of the product to @ShurAmazonBot. 545 | 546 | As product checking runs separately, commands are separated for the different tracking items: 547 | 548 | */check<1-6> * : It will start tracking that item with the number selected (1-6). Country names avaliable: *ES UK FR DE IT.* 549 | 550 | */seconds<1-6> <5-99999>* : Time between checking price of the product (default is 20s). Optional field. 551 | 552 | */price<1-6> <0-999999>* : You can set a minimum value for the price to get a notification (by default you will be notified allways if there is any change). Optional field. 553 | 554 | */cancel<1-6>* : This cancels the specified tracking. 555 | 556 | */log<1-6>* : Bot will upload the price logfile of the tracking. 557 | 558 | */settings* : To see the current status of all the tracks and configurations. 559 | 560 | *Examples of commands:* 561 | 562 | */check2 B013P2K9NC ES *: This will be checking the price of the product B013P2K9NC in Spain 563 | */log1 * : The log of track number 1 will be sent. 564 | */cancel6* : The tracking 5 will stop to check prices. 565 | */secconds5 120* : This will be set 120s to the tracking time of track 5. 566 | */price1 56* : You will only get notifications if price of track 1 drops over 56EUR/GBP 567 | 568 | - Use Notepad++ or similar to open the logfiles, otherwise the log will be shown in one line. 569 | " 570 | ;; 571 | 572 | '/res') 573 | send_message "${USER[ID]}" "$res" 574 | ;; 575 | 576 | '/id') 577 | send_message "${USER[ID]}" ":D" 578 | ;; 579 | 580 | '/start') 581 | echo ${USER[USERNAME]} ${USER[ID]} >> stats.txt 582 | send_action "${USER[ID]}" "typing" 583 | send_markdown_message "${USER[ID]}" "*Welcome* @${USER[USERNAME]} 584 | 585 | This bot tracks Amazon prices of your products all the time, this is intended to do with products that have very hight drops of price in short moments of time. 586 | 587 | When a change of price is detected, it will notify you and it will write it to a prices logfile which you can access everytime you want. 588 | 589 | *Please see* /help *to see the commands and detailed options avaliable.* 590 | 591 | *Source code* avaliable at: https://github.com/iicc1/Check4ChangeAmazonBot 592 | 593 | *By:* @iicc1" 594 | ;; 595 | 596 | # Settings 597 | '/settings') 598 | check_settings 599 | ;; 600 | 601 | # Cancel 602 | '/cancel1') 603 | cancel_check "1" 604 | ;; 605 | '/cancel2') 606 | cancel_check "2" 607 | ;; 608 | '/cancel3') 609 | cancel_check "3" 610 | ;; 611 | '/cancel4') 612 | cancel_check "4" 613 | ;; 614 | '/cancel5') 615 | cancel_check "5" 616 | ;; 617 | '/cancel6') 618 | cancel_check "6" 619 | ;; 620 | 621 | # Log 622 | '/log1') 623 | send_log "1" 624 | ;; 625 | '/log2') 626 | send_log "2" 627 | ;; 628 | '/log3') 629 | send_log "3" 630 | ;; 631 | '/log4') 632 | send_log "4" 633 | ;; 634 | '/log5') 635 | send_log "5" 636 | ;; 637 | '/log6') 638 | send_log "6" 639 | ;; 640 | 641 | '') 642 | ;; 643 | *) 644 | 645 | esac 646 | 647 | fi 648 | 649 | -------------------------------------------------------------------------------- /config/cancels.conf: -------------------------------------------------------------------------------- 1 | ------- 2 | # @Check4ChangeAmazonBot config file 3 | ------- -------------------------------------------------------------------------------- /config/minimums.conf: -------------------------------------------------------------------------------- 1 | # @Check4ChangeAmazonBot config file 2 | ------- 3 | 4 | -------------------------------------------------------------------------------- /config/run.conf: -------------------------------------------------------------------------------- 1 | # @Check4ChangeAmazonBot config file 2 | ------ 3 | -------------------------------------------------------------------------------- /config/seconds.conf: -------------------------------------------------------------------------------- 1 | # @Check4ChangeAmazonBot config file 2 | ------- 3 | --------------------------------------------------------------------------------