├── .gitignore ├── Youtube ├── youtube ├── .Makefile.un~ ├── youtube-search ├── x64 │ └── youtube-search ├── x86 │ └── youtube-search ├── update-youtubedl ├── yt.desktop ├── ytb.desktop ├── youtube-dlfast ├── manifest.json ├── youtube-search.h ├── Makefile ├── ytb.js ├── yt.js ├── youtube-safe └── youtube-search.cpp ├── Imaging ├── test ├── file.png ├── tracking ├── Makefile ├── tracking.cpp └── test.cpp ├── TextCommand ├── gvapi ├── gvoice.o ├── x64 │ ├── gvapi │ └── gtextcommand ├── gtextcommand ├── gvapi.8.gz ├── x86 │ ├── gvoice.o │ └── gtextcommand ├── .Makefile.un~ ├── Makefile ├── gvoice.h ├── gtextcommand.cpp ├── gvapi.8 ├── gvapi.cpp └── gvoice.cpp ├── Misc ├── .sayweather.sh.un~ ├── saydate.sh ├── sayweather.sh ├── checkSMSbyvoice.sh ├── check_gmail.py ├── post_facebook.py ├── facebookbyvoice.sh ├── checkmailbyvoice.sh ├── getweather.py └── textbyvoice.sh ├── VoiceCommand ├── .Makefile.un~ ├── voicecommand ├── x64 │ └── voicecommand ├── x86 │ └── voicecommand ├── voicecommand.8.gz ├── .speech-recog.sh.un~ ├── .voicecommand.cpp.un~ ├── TODO ├── google ├── commands.conf ├── Makefile ├── tts ├── voicecommand.h ├── speech-recog.sh ├── voicecommand.8 └── voicecommand.cpp ├── DownloadController ├── download ├── x64 │ └── download ├── x86 │ └── download ├── .Makefile.un~ ├── downconn.h ├── Makefile ├── download.cpp └── downconn.cpp ├── Install ├── .InstallAUISuite.sh.un~ ├── .UninstallAUISuite.sh.un~ ├── UninstallAUISuite.sh ├── UpdateAUISuite.sh └── InstallAUISuite.sh ├── PlayVideoScripts ├── playvideo.8.gz └── playvideo ├── Makefile ├── README.md └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | -------------------------------------------------------------------------------- /Youtube/youtube: -------------------------------------------------------------------------------- 1 | youtube-safe -------------------------------------------------------------------------------- /Imaging/test: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenHickson/PiAUISuite/HEAD/Imaging/test -------------------------------------------------------------------------------- /Imaging/file.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenHickson/PiAUISuite/HEAD/Imaging/file.png -------------------------------------------------------------------------------- /Imaging/tracking: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenHickson/PiAUISuite/HEAD/Imaging/tracking -------------------------------------------------------------------------------- /TextCommand/gvapi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenHickson/PiAUISuite/HEAD/TextCommand/gvapi -------------------------------------------------------------------------------- /TextCommand/gvoice.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenHickson/PiAUISuite/HEAD/TextCommand/gvoice.o -------------------------------------------------------------------------------- /TextCommand/x64/gvapi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenHickson/PiAUISuite/HEAD/TextCommand/x64/gvapi -------------------------------------------------------------------------------- /Youtube/.Makefile.un~: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenHickson/PiAUISuite/HEAD/Youtube/.Makefile.un~ -------------------------------------------------------------------------------- /Misc/.sayweather.sh.un~: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenHickson/PiAUISuite/HEAD/Misc/.sayweather.sh.un~ -------------------------------------------------------------------------------- /Misc/saydate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | current=`date` 4 | echo "$current" 5 | tts "FILLER FILL $current" 6 | -------------------------------------------------------------------------------- /TextCommand/gtextcommand: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenHickson/PiAUISuite/HEAD/TextCommand/gtextcommand -------------------------------------------------------------------------------- /TextCommand/gvapi.8.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenHickson/PiAUISuite/HEAD/TextCommand/gvapi.8.gz -------------------------------------------------------------------------------- /TextCommand/x86/gvoice.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenHickson/PiAUISuite/HEAD/TextCommand/x86/gvoice.o -------------------------------------------------------------------------------- /Youtube/youtube-search: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenHickson/PiAUISuite/HEAD/Youtube/youtube-search -------------------------------------------------------------------------------- /TextCommand/.Makefile.un~: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenHickson/PiAUISuite/HEAD/TextCommand/.Makefile.un~ -------------------------------------------------------------------------------- /VoiceCommand/.Makefile.un~: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenHickson/PiAUISuite/HEAD/VoiceCommand/.Makefile.un~ -------------------------------------------------------------------------------- /VoiceCommand/voicecommand: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenHickson/PiAUISuite/HEAD/VoiceCommand/voicecommand -------------------------------------------------------------------------------- /Youtube/x64/youtube-search: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenHickson/PiAUISuite/HEAD/Youtube/x64/youtube-search -------------------------------------------------------------------------------- /Youtube/x86/youtube-search: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenHickson/PiAUISuite/HEAD/Youtube/x86/youtube-search -------------------------------------------------------------------------------- /DownloadController/download: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenHickson/PiAUISuite/HEAD/DownloadController/download -------------------------------------------------------------------------------- /TextCommand/x64/gtextcommand: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenHickson/PiAUISuite/HEAD/TextCommand/x64/gtextcommand -------------------------------------------------------------------------------- /TextCommand/x86/gtextcommand: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenHickson/PiAUISuite/HEAD/TextCommand/x86/gtextcommand -------------------------------------------------------------------------------- /VoiceCommand/x64/voicecommand: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenHickson/PiAUISuite/HEAD/VoiceCommand/x64/voicecommand -------------------------------------------------------------------------------- /VoiceCommand/x86/voicecommand: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenHickson/PiAUISuite/HEAD/VoiceCommand/x86/voicecommand -------------------------------------------------------------------------------- /DownloadController/x64/download: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenHickson/PiAUISuite/HEAD/DownloadController/x64/download -------------------------------------------------------------------------------- /DownloadController/x86/download: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenHickson/PiAUISuite/HEAD/DownloadController/x86/download -------------------------------------------------------------------------------- /Install/.InstallAUISuite.sh.un~: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenHickson/PiAUISuite/HEAD/Install/.InstallAUISuite.sh.un~ -------------------------------------------------------------------------------- /PlayVideoScripts/playvideo.8.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenHickson/PiAUISuite/HEAD/PlayVideoScripts/playvideo.8.gz -------------------------------------------------------------------------------- /VoiceCommand/voicecommand.8.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenHickson/PiAUISuite/HEAD/VoiceCommand/voicecommand.8.gz -------------------------------------------------------------------------------- /DownloadController/.Makefile.un~: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenHickson/PiAUISuite/HEAD/DownloadController/.Makefile.un~ -------------------------------------------------------------------------------- /Install/.UninstallAUISuite.sh.un~: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenHickson/PiAUISuite/HEAD/Install/.UninstallAUISuite.sh.un~ -------------------------------------------------------------------------------- /VoiceCommand/.speech-recog.sh.un~: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenHickson/PiAUISuite/HEAD/VoiceCommand/.speech-recog.sh.un~ -------------------------------------------------------------------------------- /VoiceCommand/.voicecommand.cpp.un~: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/StevenHickson/PiAUISuite/HEAD/VoiceCommand/.voicecommand.cpp.un~ -------------------------------------------------------------------------------- /Misc/sayweather.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | zipcode=`cat $HOME/.misc | awk -F'zipcode==' '{print $2}'` 4 | result=`python /home/pi/AUI/Misc/getweather.py "$zipcode"` 5 | 6 | echo "$result" 7 | tts "FILLER FILL $result" 8 | 9 | -------------------------------------------------------------------------------- /VoiceCommand/TODO: -------------------------------------------------------------------------------- 1 | GUI interaction 2 | Take answer functionality out and make it it's own program 3 | Figure out audio bug which skips first couple of seconds 4 | Figure out how to cancel out audio coming from speakers, like music (long long term) 5 | -------------------------------------------------------------------------------- /Youtube/update-youtubedl: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # cron script to save a update youtube-dl. 4 | # 5 | # Written by Steven Hickson for the playvideo project. 6 | # 7 | youtube-dl -U 8 | -------------------------------------------------------------------------------- /Youtube/yt.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Encoding=UTF-8 3 | Name=Youtube 4 | Type=Application 5 | Exec=/usr/bin/youtube %u 6 | Icon=web-browser 7 | Terminal=false 8 | Type=Application 9 | Categories=AudioVideo; 10 | MimeType=x-scheme-handler/yt 11 | NoDisplay=true 12 | -------------------------------------------------------------------------------- /Youtube/ytb.desktop: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Encoding=UTF-8 3 | Name=YoutubeSafe 4 | Type=Application 5 | Exec=/usr/bin/youtube-safe %u 6 | Icon=web-browser 7 | Terminal=false 8 | Type=Application 9 | Categories=AudioVideo; 10 | MimeType=x-scheme-handler/ytb 11 | NoDisplay=true 12 | -------------------------------------------------------------------------------- /VoiceCommand/google: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | for var in "$@" 5 | do 6 | if [ -z $search_string ] ; then 7 | search_string="https://www.google.com/#hl=en&safe=off&output=search&q=$var" 8 | else 9 | search_string="$search_string+$var" 10 | fi 11 | done 12 | 13 | midori -a "$search_string" 14 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | all: 3 | cd DownloadController; make 4 | cd Imaging; make 5 | cd TextCommand; make 6 | cd VoiceCommand; make 7 | cd Youtube; make 8 | 9 | clean: 10 | cd DownloadController; make clean 11 | cd Imaging; make clean 12 | cd TextCommand; make clean 13 | cd VoiceCommand; make clean 14 | cd Youtube; make clean 15 | 16 | install: 17 | cd Install; ./InstallAUISuite.sh 18 | -------------------------------------------------------------------------------- /Misc/checkSMSbyvoice.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | filler="FILLER FILL" 4 | texts=`gvapi -c` 5 | if [ "$texts" != "" ] ; then 6 | echo "Found a message" 7 | name=`echo $texts | awk -F':' '{print $1}'` 8 | message=`echo $texts | awk -F':' '{print $2}'` 9 | tts "$filler message from $name" 10 | sleep 0.5 11 | tts "$filler $message" 12 | else 13 | echo "No messages" 14 | tts "$filler no messages" 15 | fi 16 | -------------------------------------------------------------------------------- /Youtube/youtube-dlfast: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [ $# -ne 2 ] 3 | then 4 | echo "Usage : $0 " 5 | echo "e.g : $0 http://www.youtube.com/watch?v=D1R-jKKp3NA steve_jobs" 6 | else 7 | #outputfile=".avi" 8 | todnload=`youtube-dl -g $1 | tail -n 1 -` 9 | echo "Got the file.."$todnload 10 | axel -n 100 $todnload -o $2".flv" # wget -c $todnload -O $2".flv" .if you don't use axel 11 | #echo "Download Completed..." 12 | #ffmpeg -i $2".flv" $2$outputfile # get the avi file 13 | fi 14 | -------------------------------------------------------------------------------- /Misc/check_gmail.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import feedparser 3 | import string 4 | import sys 5 | 6 | USERNAME = str(sys.argv[1]); 7 | PASSWORD = str(sys.argv[2]); 8 | 9 | response = feedparser.parse("https://" + USERNAME + ":" + PASSWORD + "@mail.google.com/gmail/feed/atom") 10 | unread_count = int(response["feed"]["fullcount"]) 11 | 12 | if unread_count > 20: 13 | unread_count = 20 14 | 15 | for i in range(0,unread_count): 16 | name = response['items'][i].author.split("("); 17 | print "Message from: " + name[0] + "says: " + response['items'][i].title 18 | -------------------------------------------------------------------------------- /Youtube/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 2, 3 | "content_scripts": [ { 4 | "exclude_globs": [ ], 5 | "include_globs": [ "*" ], 6 | "js": [ "yt.js", 7 | "ytb.js" 8 | ], 9 | "matches": ["http://*/*", 10 | "https://*/*" 11 | ], 12 | "run_at": "document_end" 13 | } ], 14 | "converted_from_user_script": true, 15 | "description": "YouTube replace video script!", 16 | "name": "ReplaceVideo", 17 | "version": "1" 18 | } 19 | -------------------------------------------------------------------------------- /Misc/post_facebook.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import smtplib 3 | import string 4 | import sys 5 | import getopt 6 | from email.mime.text import MIMEText 7 | 8 | USERNAME = str(sys.argv[1]); 9 | PASSWORD = str(sys.argv[2]); 10 | MAILTO = "trigger@ifttt.com" 11 | 12 | s = ' '.join(sys.argv[3:]) 13 | msg = MIMEText(s) 14 | msg['Subject'] = '#facebook' 15 | msg['From'] = USERNAME 16 | msg['To'] = MAILTO 17 | 18 | server = smtplib.SMTP('smtp.gmail.com:587') 19 | server.ehlo_or_helo_if_needed() 20 | server.starttls() 21 | server.ehlo_or_helo_if_needed() 22 | server.login(USERNAME,PASSWORD) 23 | server.sendmail(USERNAME, MAILTO, msg.as_string()) 24 | server.quit() 25 | -------------------------------------------------------------------------------- /Misc/facebookbyvoice.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | user=`cat $HOME/.misc | awk -F'username==' '{print $2}' | tr -d '\n'` 3 | pass=`cat $HOME/.misc | awk -F'password==' '{print $2}' | tr -d '\n'` 4 | 5 | okay=0 6 | filler="FILLER FILL" 7 | tts "$filler What would you like to post" 8 | while [ $okay == 0 ] 9 | do 10 | message=`speech-recog.sh -d 10 | tr -d '"'` 11 | tts "$filler I got $message. Is this correct?" 12 | yes=`speech-recog.sh` 13 | if [[ "$yes" == *"yes"* ]] ; then 14 | python /home/pi/AUI/Misc/post_facebook.py "$user" "$pass" "$message" 15 | okay=1 16 | exit 17 | else 18 | tts "$filler Okay try again" 19 | fi 20 | done 21 | -------------------------------------------------------------------------------- /Youtube/youtube-search.h: -------------------------------------------------------------------------------- 1 | #ifndef __DOWNCONN_H__ 2 | #define __DOWNCONN_H__ 3 | 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | #define DATA_SIZE 200 10 | 11 | class Youtube { 12 | private: 13 | CURL *hcurl; 14 | CURLcode cr; 15 | bool use_pass, init; 16 | protected: 17 | string version; 18 | public: 19 | char errorbuf[CURL_ERROR_SIZE]; 20 | string curlbuf; 21 | 22 | int debug; 23 | Youtube(); 24 | ~Youtube(); 25 | 26 | int Search(string query, string *link, bool verify); 27 | int PlayVideo(string video, bool verify); 28 | 29 | int Init(void); 30 | 31 | static int CurlWriter(char *data, size_t size, size_t nmemb, string *buffer); 32 | }; 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /Misc/checkmailbyvoice.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | filler="FILLER FILL" 4 | #Message from: name says: message 5 | user=`cat $HOME/.misc | awk -F'username==' '{print $2}' | tr -d '\n'` 6 | pass=`cat $HOME/.misc | awk -F'password==' '{print $2}' | tr -d '\n'` 7 | 8 | texts=`python /home/pi/AUI/Misc/check_gmail.py "$user" "$pass"` 9 | if [ "$texts" != "" ] ; then 10 | echo "Found a message" 11 | printf "%s\n" "$texts" | 12 | while IFS= read -r line 13 | do 14 | name=${line#*from:} 15 | name=${name%says:*} 16 | message=${line#*says:} 17 | echo "message from $name" 18 | tts "$filler message from $name" 19 | sleep 0.5 20 | echo " $message" 21 | tts "$filler $message" 22 | done 23 | else 24 | echo "No messages" 25 | tts "$filler no messages" 26 | fi 27 | -------------------------------------------------------------------------------- /DownloadController/downconn.h: -------------------------------------------------------------------------------- 1 | #ifndef __DOWNCONN_H__ 2 | #define __DOWNCONN_H__ 3 | 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | 9 | #define DATA_SIZE 200 10 | 11 | class Downloader { 12 | private: 13 | CURL *hcurl; 14 | CURLcode cr; 15 | string host; 16 | string port; 17 | string username; 18 | string password; 19 | bool use_pass, init; 20 | protected: 21 | string version; 22 | public: 23 | char errorbuf[CURL_ERROR_SIZE]; 24 | string curlbuf; 25 | 26 | int debug; 27 | Downloader(); 28 | ~Downloader(); 29 | 30 | int Search(string download, string *link, bool verify); 31 | int DownloadTorrent(string torrent); 32 | 33 | int Init(void); 34 | int SetTransmissionParams(void); 35 | 36 | static int CurlWriter(char *data, size_t size, size_t nmemb, string *buffer); 37 | }; 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /Imaging/Makefile: -------------------------------------------------------------------------------- 1 | 2 | ip_cam: ip_cam.cpp 3 | g++ -O3 -mcpu=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard ip_cam.cpp -I/ffmpeg_compiled/usr/local/include -I/usr/local/include -L/usr/local/lib/ -L/ffmpeg_compiled/usr/local/lib -lopencv_core -lopencv_highgui -lopencv_objdetect -lopencv_imgproc -lopencv_videoio -o ip_cam 4 | 5 | test: test.cpp 6 | g++ -O3 -mcpu=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard test.cpp -I/ffmpeg_compiled/usr/local/include -I/usr/include -L/usr/lib/ -L/ffmpeg_compiled/usr/local/lib -lopencv_core -lopencv_highgui -lopencv_objdetect -lopencv_imgproc -o test 7 | 8 | tracking: tracking.cpp 9 | g++ -O3 -mcpu=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard tracking.cpp -I/ffmpeg_compiled/usr/local/include -I/usr/include -L/usr/lib/ -L/ffmpeg_compiled/usr/local/lib -lopencv_core -lopencv_highgui -lopencv_objdetect -lopencv_imgproc -o tracking 10 | 11 | clean: 12 | rm *.o test tracking 2>/dev/null 13 | 14 | -------------------------------------------------------------------------------- /VoiceCommand/commands.conf: -------------------------------------------------------------------------------- 1 | #This is the default config file 2 | #These are the special options you can set (remove the #) 3 | #!verify==1 4 | #!keyword==pi 5 | #!thresh==0.7 6 | #!continuous==1 7 | #!response==Yes Sir? 8 | #!quiet==0 9 | #!ignore==0 10 | #!filler==0 11 | #!duration==2 12 | #!com_dur==3 13 | #!hardware==plughw:1,0 14 | #Here are the commands 15 | show me==/home/pi/AUI/Imaging/test 2 16 | track me==/home/pi/AUI/Imaging/test 1 17 | download==download ... 18 | play $1 season $2 episode $3==playvideo -s $2 -e $3 $1 19 | download $1 season $2 episode $3==download $1 s$2e$3 20 | play==playvideo -r -f ... 21 | multiple==playvideo -r -m -c 5 ... 22 | download==download ... 23 | YouTube==youtube-search ... 24 | Google==google ... 25 | ~music==xterm -e pianobar 26 | ~weather==/home/pi/AUI/Misc/sayweather.sh 27 | ~made you==tts "I was created by Steven Hickson" 2>/dev/null 28 | ~music==xterm -e control-pianobar.sh play 29 | ~terminal==xterm & 30 | ~Internet==midori & 31 | -------------------------------------------------------------------------------- /DownloadController/Makefile: -------------------------------------------------------------------------------- 1 | #GITREV = -D'GITREV="$(shell git log -1 --pretty=format:"%h by %an on %ai")"' 2 | BLDDEF = -D'BUILDTS="$(shell date +"%y%m%d %H:%M:%S %z")"' 3 | 4 | #Set Architecture 5 | ARCH := arm-v7 6 | DEVEL := rel 7 | LIBS := -lcurl -lboost_regex 8 | 9 | 10 | #Compilers 11 | ifeq ($(ARCH),arm-v7) 12 | CC := g++-4.8 -mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard 13 | else 14 | ifeq ($(ARCH),arm) 15 | CC := g++ -mcpu=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard 16 | else 17 | ifeq ($(ARCH),x86) 18 | CC := g++ -m32 19 | OUTPUT := x86/ 20 | else 21 | CC := g++ 22 | OUTPUT := x64/ 23 | endif 24 | endif 25 | endif 26 | 27 | #devel flags 28 | ifeq ($(BUILD),devel) 29 | FLAGS := -g -Wall 30 | else 31 | FLAGS := -O3 32 | endif 33 | 34 | download: download.cpp downconn.cpp downconn.h 35 | $(CC) $(BLDDEF) $(FLAGS) $(LIBS) -o $(addprefix $(OUTPUT), download) downconn.cpp download.cpp 36 | 37 | clean: 38 | rm *.o download 2>/dev/null 39 | 40 | install: download 41 | install download /usr/bin/download 42 | -------------------------------------------------------------------------------- /DownloadController/download.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "downconn.h" 5 | 6 | using namespace std; 7 | 8 | void PrintUsage(void); 9 | 10 | int main(int argc, char *argv[]) { 11 | Downloader down; 12 | 13 | if(argc < 2) { 14 | PrintUsage(); 15 | return -1; 16 | } 17 | 18 | down.debug = 1; 19 | 20 | string search = ""; 21 | for(int i = 1; i < argc; ++i) { 22 | if(i != 1) 23 | search += "%20"; 24 | search += string(argv[i]); 25 | } 26 | if (down.Init()) { 27 | cout << "Curl failed to initialize. Dying.\n"; 28 | return -1; 29 | } 30 | string link; 31 | down.Search(search, &link, false); 32 | down.DownloadTorrent(link); 33 | return 0; 34 | } 35 | 36 | void PrintUsage(void) { 37 | printf("Just type what you want it to download like you would search on a website.\nEx: download Futurama S07E08 HD\n"); 38 | printf("Copyright GPL v3 Steven Hickson 2013\n"); 39 | } 40 | 41 | 42 | -------------------------------------------------------------------------------- /Youtube/Makefile: -------------------------------------------------------------------------------- 1 | #GITREV = -D'GITREV="$(shell git log -1 --pretty=format:"%h by %an on %ai")"' 2 | BLDDEF = -D'BUILDTS="$(shell date +"%y%m%d %H:%M:%S %z")"' 3 | 4 | #Set Architecture 5 | ARCH := arm-v7 6 | DEVEL := rel 7 | LIBS := -lcurl -lboost_regex 8 | 9 | #Compilers 10 | ifeq ($(ARCH),arm-v7) 11 | CC := g++-4.8 -mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard 12 | else 13 | ifeq ($(ARCH),arm) 14 | CC := g++ -mcpu=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard 15 | else 16 | ifeq ($(ARCH),x86) 17 | CC := g++ -m32 18 | OUTPUT := x86/ 19 | else 20 | CC := g++ 21 | OUTPUT := x64/ 22 | endif 23 | endif 24 | endif 25 | 26 | #devel flags 27 | ifeq ($(BUILD),devel) 28 | FLAGS := -g -Wall 29 | else 30 | FLAGS := -O3 31 | endif 32 | 33 | youtube-search: youtube-search.h youtube-search.cpp 34 | $(CC) $(BLDDEF) $(FLAGS) $(LIBS) -o $(addprefix $(OUTPUT), youtube-search) youtube-search.cpp 35 | 36 | clean: 37 | rm *.o youtube-search 2>/dev/null 38 | 39 | install: youtube youtube-dlfast youtube-search 40 | install youtube /usr/bin/youtube 41 | install youtube-dlfast /usr/bin/youtube-dlfast 42 | install youtube-search /usr/bin/youtube-search 43 | -------------------------------------------------------------------------------- /VoiceCommand/Makefile: -------------------------------------------------------------------------------- 1 | #GITREV = -D'GITREV="$(shell git log -1 --pretty=format:"%h by %an on %ai")"' 2 | BLDDEF = -D'BUILDTS="$(shell date +"%y%m%d %H:%M:%S %z")"' 3 | 4 | #Set Architecture 5 | ARCH := arm-v7 6 | DEVEL := rel 7 | LIBS := -lcurl -lboost_regex 8 | 9 | #Compilers 10 | ifeq ($(ARCH),arm-v7) 11 | CC := g++-4.8 -mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard 12 | else 13 | ifeq ($(ARCH),arm) 14 | CC := g++ -mcpu=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard 15 | else 16 | ifeq ($(ARCH),x86) 17 | CC := g++ -m32 18 | OUTPUT := x86/ 19 | else 20 | CC := g++ 21 | OUTPUT := x64/ 22 | endif 23 | endif 24 | endif 25 | 26 | #devel flags 27 | ifeq ($(BUILD),devel) 28 | FLAGS := -g -Wall 29 | else 30 | FLAGS := -O3 31 | endif 32 | 33 | voicecommand: voicecommand.cpp voicecommand.h 34 | $(CC) $(BLDDEF) $(FLAGS) $(LIBS) -o $(addprefix $(OUTPUT), voicecommand) voicecommand.cpp 35 | 36 | clean: 37 | rm *.o voicecommand 2>/dev/null 38 | 39 | install: google speech-recog.sh voicecommand tts tts-nofill 40 | install google /usr/bin/google 41 | install tts /usr/bin/tts 42 | install speech-recog.sh /usr/bin/speech-recog.sh 43 | install voicecommand /usr/bin/voicecommand 44 | -------------------------------------------------------------------------------- /TextCommand/Makefile: -------------------------------------------------------------------------------- 1 | BLDDEF = -D'BUILDTS="$(shell date +"%y%m%d %H:%M:%S %z")"' 2 | 3 | #Set Architecture 4 | ARCH := arm-v7 5 | DEVEL := rel 6 | LIBS := -lcurl -lboost_regex 7 | 8 | #Compilers 9 | ifeq ($(ARCH),arm-v7) 10 | CC := g++-4.8 -mcpu=cortex-a7 -mfpu=neon-vfpv4 -mfloat-abi=hard 11 | else 12 | ifeq ($(ARCH),arm) 13 | CC := g++ -mcpu=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard 14 | else 15 | ifeq ($(ARCH),x86) 16 | CC := g++ -m32 17 | OUTPUT := x86/ 18 | else 19 | CC := g++ 20 | OUTPUT := x64/ 21 | endif 22 | endif 23 | endif 24 | 25 | #devel flags 26 | ifeq ($(BUILD),devel) 27 | FLAGS := -g -Wall 28 | else 29 | FLAGS := -O3 30 | endif 31 | 32 | gtextcommand: gtextcommand.cpp gvoice.cpp gvoice.h 33 | $(CC) $(BLDDEF) $(FLAGS) $(LIBS) -o $(addprefix $(OUTPUT), gtextcommand) $(addprefix $(OUTPUT), gvoice.o) gtextcommand.cpp 34 | 35 | gvapi: gvapi.cpp gvoice.cpp gvoice.h 36 | $(CC) $(BLDDEF) $(FLAGS) $(LIBS) -o $(addprefix $(OUTPUT), gvapi) $(addprefix $(OUTPUT), gvoice.o) gvapi.cpp 37 | 38 | gvoice: gvoice.cpp gvoice.h 39 | $(CC) $(BLDDEF) $(FLAGS) $(LIBS) -c -o $(addprefix $(OUTPUT), gvoice.o) gvoice.cpp 40 | 41 | clean: 42 | rm *.o gtextcommand gvapi 2>/dev/null 43 | 44 | install: gtextcommand 45 | install gtextcommand /usr/bin/gtextcommand 46 | install gtextcommand /usr/bin/gvapi 47 | -------------------------------------------------------------------------------- /Misc/getweather.py: -------------------------------------------------------------------------------- 1 | import pywapi 2 | import string 3 | import sys 4 | 5 | #this requires pywapi which can be installed from https://code.google.com/p/python-weather-api/ 6 | #If in the US 00000 should be your area code 7 | #If in Britain, try using the BBC weather scripts found here: https://github.com/duncanj/voice_scripts 8 | 9 | # pass a second parameter, 'imperial' if you are feeling like ferinheight instead of celsius 10 | result = pywapi.get_weather_from_weather_com(str(sys.argv[1])) 11 | 12 | print "It is " + string.lower(result['current_conditions']['text']) + " and " + result['current_conditions']['temperature'] + " degrees." 13 | print "Humidity " + result['current_conditions']['humidity'] + " percent." 14 | 15 | today = result['forecasts'][0] 16 | highToday = today['high'] 17 | if highToday > result['current_conditions']['temperature']: 18 | print "The expected high is " + highToday + "." 19 | 20 | print "Overnight, " + today['night']['text'] + " with a low of " + today['low'] + " " 21 | if today['night']['chance_precip'] != "0": 22 | print " and a " + today['night']['chance_precip'] + " percent chance of rain." 23 | 24 | tomorrow = result['forecasts'][1] 25 | print "Tomorrow, "+ tomorrow['day']['text'] + " with a high of " + tomorrow['high'] + " " 26 | 27 | if tomorrow['day']['chance_precip'] != "0": 28 | print " and a " + tomorrow['day']['chance_precip'] + " percent chance of rain." 29 | -------------------------------------------------------------------------------- /TextCommand/gvoice.h: -------------------------------------------------------------------------------- 1 | #ifndef __GVOICE_H__ 2 | #define __GVOICE_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define DTFILE "/dev/shm/time" 9 | 10 | using namespace std; 11 | 12 | class GoogleVoice { 13 | CURL *hcurl; 14 | CURLcode cr; 15 | string email,passwd,myNum; 16 | string rnr_se; // Session token that Google needs. 17 | protected: 18 | string version; 19 | public: 20 | char errorbuf[CURL_ERROR_SIZE]; 21 | string curlbuf; 22 | string contact_buf; 23 | 24 | int loggedin; 25 | int debug; // Temp flag used to mostly dump the contents of curlbuf. 26 | GoogleVoice(); 27 | ~GoogleVoice(); 28 | 29 | int Init(void); 30 | int Login(); 31 | int Login(string login, string passwd); 32 | //int Logout(void); 33 | 34 | int GetContactInfo(); 35 | int SendSMS(string number, string msg); 36 | int CheckSMS(string &results, string number, string keyword, bool delete_sms); 37 | int MarkAsRead(string msg_id); 38 | int DeleteSMS(string msg_id); 39 | int BlockSMS(string msg_id); 40 | int CallNumber(string to, string from); 41 | void Get_rnr(string &rnr) { 42 | rnr = rnr_se; 43 | } 44 | void Set_rnr(string rnr) { 45 | rnr_se = rnr; 46 | loggedin = 1; 47 | } 48 | void Logout(void) { 49 | rnr_se = ""; 50 | loggedin = 0; 51 | } 52 | 53 | static int CurlWriter(char *data, size_t size, size_t nmemb, string *buffer); 54 | }; 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /Misc/textbyvoice.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #we need a contacts folder, this will be obtained and updated using gvapi -i and will be in ~/.contacts 4 | 5 | function sendtext() { 6 | local filler="FILLER FILL" 7 | local arrs=`echo "$1" | tr "==" "\n"` 8 | local count=1 9 | local okay=0 10 | while read -r x 11 | do 12 | if [ "$count" == 1 ] ; then 13 | tts "$filler What would you like to text to $x" 14 | elif [ "$count" == 3 ] ; then 15 | while [ $okay == 0 ] 16 | do 17 | local message=`speech-recog.sh -d 10 | tr -d '"'` 18 | tts "$filler I got $message. Is this correct?" 19 | yes=`speech-recog.sh` 20 | if [[ "$yes" == *"yes"* ]] ; then 21 | gvapi -n "$x" -m "$message" 22 | okay=1 23 | exit 24 | fi 25 | done 26 | fi 27 | count=`echo "$count + 1" | bc` 28 | done <<< "$arrs" 29 | } 30 | 31 | if [ $# -gt 0 ] ; then 32 | if [ $1 == "-u" ] ; then 33 | echo "Updating contacts" 34 | gvapi -i > ~/.contacts 35 | exit 36 | fi 37 | 38 | results=`cat ~/.contacts | grep -i "$@"` 39 | num=`echo "$results" | wc -l` 40 | if [ $num -gt 1 ] ; then 41 | echo "not done yet" 42 | elif [ $num == 1 ] ; then 43 | #I need to split the string 44 | sendtext "$results" 45 | fi 46 | else 47 | echo "Found no var" 48 | fi 49 | -------------------------------------------------------------------------------- /VoiceCommand/tts: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #for the Raspberry Pi, we need to insert some sort of FILLER here since it cuts off the first bit of audio 4 | 5 | string=$@ 6 | lang="en" 7 | if [ "$1" == "-l" ] ; then 8 | lang="$2" 9 | string=`echo "$string" | sed -r 's/^.{6}//'` 10 | fi 11 | 12 | #empty the original file 13 | echo "" > "/dev/shm/speak.mp3" 14 | 15 | len=${#string} 16 | while [ $len -ge 100 ] ; 17 | do 18 | #lets split this up so that its a maximum of 99 characters 19 | tmp=${string:0:100} 20 | string=${string:100} 21 | 22 | #now we need to make sure there aren't split words, let's find the last space and the string after it 23 | lastspace=${tmp##* } 24 | tmplen=${#lastspace} 25 | 26 | #here we are shortening the tmp string 27 | tmplen=`expr 100 - $tmplen` 28 | tmp=${tmp:0:tmplen} 29 | 30 | #now we concatenate and the string is reconstructed 31 | string="$lastspace$string" 32 | len=${#string} 33 | 34 | #get the first 100 characters 35 | wget -q -U Mozilla -O "/dev/shm/tmp.mp3" "https://translate.google.com/translate_tts?tl=${lang}&q=$tmp&ie=UTF-8&total=1&idx=0&client=t" 36 | cat "/dev/shm/tmp.mp3" >> "/dev/shm/speak.mp3" 37 | done 38 | #this will get the last remnants 39 | wget -q -U Mozilla -O "/dev/shm/tmp.mp3" "https://translate.google.com/translate_tts?tl=${lang}&q=$string&ie=UTF-8&total=1&idx=0&client=t" 40 | cat "/dev/shm/tmp.mp3" >> "/dev/shm/speak.mp3" 41 | #now we finally say the whole thing 42 | cat "/dev/shm/speak.mp3" | mpg123 - 1>>/dev/shm/voice.log 2>>/dev/shm/voice.log 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Alternative User Interface 2 | 3 | Includes voicecommand, download, playvideo, and textcommand scripts 4 | 5 | This requires: 6 | 7 | * boost 8 | * curl 9 | * xterm 10 | * espeak 11 | * some other things 12 | 13 | To install the dependencies, run: 14 | ```bash 15 | sudo apt-get install -y libboost-dev libboost-regex-dev youtube-dl axel curl xterm libcurl4-gnutls-dev mpg123 flac sox 16 | ``` 17 | 18 | To install PiAUISuite: 19 | ```bash 20 | git clone https://github.com/StevenHickson/PiAUISuite.git 21 | cd PiAUISuite/Install 22 | ./InstallAUISuite.sh 23 | ``` 24 | 25 | It will: 26 | * ask if you want to install the dependencies 27 | * to install each script 28 | 29 | ## Different Parts 30 | 31 | Name | Purpose | Blogpost 32 | -----|---------|--------- 33 | playvideo | finds and plays videos | [Here](http://stevenhickson.blogspot.com/2013/03/playing-videos-intelligently-with.html) 34 | downloader | find and downloads the best torrent | [Here](http://stevenhickson.blogspot.com/2013/03/automatically-downloading-torrents-with.html) 35 | gvapi | checks, sends, and deletes SMS messages | [Here](http://stevenhickson.blogspot.com/2013/05/using-google-voice-c-api.html) 36 | gtextcommand | checks for sms messages every minute and runs commands from them | [Here](http://stevenhickson.blogspot.com/2013/03/controlling-raspberry-pi-via-text.html) 37 | youtube | streams youtube | [In browser](http://stevenhickson.blogspot.com/2013/06/playing-youtube-videos-in-browser-on.html) and [on Pi](http://stevenhickson.blogspot.com/2013/04/using-youtube-on-raspberry-pi-without.html) 38 | youtube-safe | streams other video files | [Hulu and Vimeo](http://stevenhickson.blogspot.com/2013/06/getting-huluvimeo-to-work-on-raspberry.html) and [others](http://stevenhickson.blogspot.com/2013/06/streaming-other-hd-video-sites-on.html) 39 | voicecommand | run voice commands | [Here](http://stevenhickson.blogspot.com/2013/05/voice-command-v20-for-raspberry-pi.html) and [here](http://stevenhickson.blogspot.com/2013/04/voice-control-on-raspberry-pi.html) 40 | 41 | Copyright 42 | 43 | [GPLv3](https://tldrlegal.com/license/gnu-general-public-license-v3-(gpl-3)) 44 | 45 | Steven Hickson 46 | -------------------------------------------------------------------------------- /VoiceCommand/voicecommand.h: -------------------------------------------------------------------------------- 1 | #ifndef __VOICECOMMAND_H__ 2 | #define __VOICECOMMAND_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #define DATA_SIZE 200 21 | #define DURATION_DEFAULT "3" 22 | #define COM_DURATION_DEFAULT "2" 23 | 24 | using namespace std; 25 | 26 | class VoiceCommand { 27 | private: 28 | CURL *hcurl; 29 | CURLcode cr; 30 | bool use_pass, init; 31 | vector voice, commands; 32 | protected: 33 | string version; 34 | public: 35 | bool continuous; 36 | bool verify; 37 | bool edit; 38 | bool ignoreOthers; 39 | bool quiet; 40 | bool differentHW; 41 | bool passthrough; 42 | float thresh; 43 | //I'm storing the durations as strings because it makes the commands less messy and requires less overhead 44 | string duration; 45 | string command_duration; 46 | string filler; 47 | string recordHW; 48 | string keyword; 49 | string config_file; 50 | string response; 51 | string improper; 52 | string lang; 53 | string api; 54 | string forced_input; 55 | string pid_file; 56 | int maxResponse; 57 | 58 | char errorbuf[CURL_ERROR_SIZE]; 59 | string curlbuf; 60 | 61 | int debug; 62 | VoiceCommand(); 63 | ~VoiceCommand(); 64 | 65 | inline void ProcessMessage(const char* message); 66 | void GetConfig(); 67 | void EditConfig(); 68 | void CheckConfig(); 69 | inline void CheckConfigParam(int argc, char* argv[]); 70 | inline void CheckCmdLineParam(int argc, char* argv[]); 71 | void DisplayUsage(); 72 | void Setup(); 73 | 74 | int Speak(string message); 75 | int Search(const char* search); 76 | int Init(void); 77 | 78 | static int CurlWriter(char *data, size_t size, size_t nmemb, string *buffer); 79 | }; 80 | 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /VoiceCommand/speech-recog.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | hardware="plughw:1,0" 4 | duration="3" 5 | lang="en" 6 | hw_bool=0 7 | dur_bool=0 8 | lang_bool=0 9 | for var in "$@" 10 | do 11 | if [ "$var" == "-D" ] ; then 12 | hw_bool=1 13 | elif [ "$var" == "-d" ] ; then 14 | dur_bool=1 15 | elif [ "$var" == "-l" ] ; then 16 | lang_bool=1 17 | elif [ $hw_bool == 1 ] ; then 18 | hw_bool=0 19 | hardware="$var" 20 | elif [ $dur_bool == 1 ] ; then 21 | dur_bool=0 22 | duration="$var" 23 | elif [ $lang_bool == 1 ] ; then 24 | lang_bool=0 25 | lang="$var" 26 | else 27 | echo "Invalid option, valid options are -D for hardware and -d for duration" 28 | fi 29 | done 30 | 31 | #this works really inconsistently and I don't know why. I would love to implement it 32 | #sox -r 16000 -t alsa $hardware /dev/shm/out.flac silence 1 0.3 1% 1 0.5 1% 33 | #wget -q -U "rate=16000" -O - --post-file /dev/shm/out.flac --header="Content-Type: audio/x-flac; rate=16000" "http://www.google.com/speech-api/v1/recognize?lang=en&client=Mozilla/5.0" | sed -e 's/[{}]/''/g'| awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]; exit }' | awk -F: 'NR==3 { print $3; exit }' 34 | #arecord -D $hardware -f cd -t wav -d $duration -r 16000 | flac - -f --best --sample-rate 16000 -o /dev/shm/out.flac 1>/dev/shm/voice.log 2>/dev/shm/voice.log; wget -O - -o /dev/null --post-file /dev/shm/out.flac --header="Content-Type: audio/x-flac; rate=16000" http://www.google.com/speech-api/v1/recognize?lang="$lang" | sed -e 's/[{}]/''/g'| awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]; exit }' | awk -F: 'NR==3 { print $3; exit }' 35 | arecord -D $hardware -t wav -d $duration -r 16000 | flac - -f --best --sample-rate 16000 -o /dev/shm/out.flac 1>/dev/shm/voice.log 2>/dev/shm/voice.log; curl -X POST --data-binary @/dev/shm/out.flac --user-agent 'Mozilla/5.0' --header 'Content-Type: audio/x-flac; rate=16000;' "https://www.google.com/speech-api/v2/recognize?output=json&lang=$lang&key=AIzaSyBOti4mM-6x9WDnZIjIeyEU21OpBXqWBgw&client=Mozilla/5.0" | sed -e 's/[{}]/''/g' | awk -F":" '{print $4}' | awk -F"," '{print $1}' | tr -d '\n' 36 | 37 | rm /dev/shm/out.flac 38 | -------------------------------------------------------------------------------- /Install/UninstallAUISuite.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #Script to make install of AUI Suite very easy 4 | 5 | function playvideo() { 6 | USER_HOME="$1" 7 | #Uninstall playvideo script 8 | echo "Uninstalling playvideo" 9 | sudo rm -f /usr/bin/playvideo 10 | sudo rm -f "$USER_HOME/.media.db" 11 | sudo rm -f /usr/share/man/man8/playvideo.8.gz 12 | sudo rm -f /etc/cron.daily/updatelocaldb 13 | } 14 | 15 | function download() { 16 | USER_HOME="$1" 17 | echo "Uninstalling downloader script" 18 | sudo rm -f "$USER_HOME/.down.info" 19 | sudo rm /usr/bin/download 20 | } 21 | 22 | function gvapi() { 23 | USER_HOME="$1" 24 | echo "Uninstalling gvapi script" 25 | sudo rm -f "$USER_HOME/.gv" 26 | sudo rm -f /usr/bin/gvapi 27 | sudo rm -f /usr/share/man/man8/gvapi.8.gz 28 | } 29 | 30 | function gtextcommand { 31 | USER_HOME="$1" 32 | echo "Uninstalling gtextcommand script" 33 | sudo rm -f "$USER_HOME/.gtext" 34 | sudo rm -f /usr/bin/gtextcommand 35 | sudo rm -f /etc/cron.d/gtextcommand 36 | } 37 | 38 | function youtube() { 39 | USER_HOME="$1" 40 | echo "Uninstalling youtube scripts" 41 | sudo rm -f /usr/bin/youtube 42 | sudo rm -f /usr/bin/youtube-safe 43 | sudo rm -f /usr/bin/youtube-dlfast 44 | sudo rm -f /usr/bin/youtube-search 45 | sudo rm -f /usr/share/applications/yt.desktop 46 | sudo rm -f /usr/share/applications/ytb.desktop 47 | sudo rm -f "$USER_HOME/.local/share/midori/scripts/yt.js" 48 | sudo rm -f "$USER_HOME/.local/share/midori/scripts/ytb.js" 49 | } 50 | 51 | function voicecommand() { 52 | echo "Uninstalling voicecommand scripts" 53 | sudo rm -f /usr/bin/voicecommand 54 | sudo rm -f /usr/bin/google 55 | sudo rm -f /usr/bin/tts 56 | sudo rm -f /usr/bin/speech-recog.sh 57 | sudo rm -f /usr/share/man/man8/voicecommand.8.gz 58 | } 59 | 60 | if [ "$(id -u)" != "0" ]; then 61 | USER_HOME="$HOME" 62 | else 63 | USER_HOME="/home/${SUDO_USER}" 64 | fi 65 | 66 | ARG="$1" 67 | if [ "$ARG" == "playvideo" ] ; then 68 | playvideo "$USER_HOME" 69 | elif [ "$ARG" == "download" ] ; then 70 | download "$USER_HOME" 71 | elif [ "$ARG" == "gtextcommand" ] ; then 72 | gtextcommand "$USER_HOME" 73 | elif [ "$ARG" == "gvapi" ] ; then 74 | gvapi "$USER_HOME" 75 | elif [ "$ARG" == "youtube" ] ; then 76 | youtube "$USER_HOME" 77 | elif [ "$ARG" == "voicecommand" ] ; then 78 | voicecommand "$USER_HOME" 79 | else 80 | playvideo "$USER_HOME" 81 | download "$USER_HOME" 82 | gtextcommand "$USER_HOME" 83 | gvapi "$USER_HOME" 84 | youtube "$USER_HOME" 85 | voicecommand "$USER_HOME" 86 | fi 87 | -------------------------------------------------------------------------------- /TextCommand/gtextcommand.cpp: -------------------------------------------------------------------------------- 1 | // Text Message Commander Steven Hickson 2013. 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "gvoice.h" 7 | 8 | using namespace std; 9 | using namespace boost; 10 | 11 | #define DATA_SIZE 200 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | GoogleVoice gv; 16 | int r; 17 | if(argc == 2) gv.debug = 3; 18 | //read username, password, valid number, and keyword from safe file 19 | FILE *fp; 20 | char *passPath; 21 | passPath = getenv("HOME"); 22 | if(passPath == NULL) { 23 | printf("Could not get $HOME\n"); 24 | return -1; 25 | } 26 | string path = string(passPath); 27 | path += "/.gtext"; 28 | fp = fopen(path.c_str(),"r"); 29 | if(!fp) {cout << "Couldn't open password file. Dying\n"; return -1;} 30 | char buf1[100]; 31 | char buf2[100]; 32 | char buf3[100]; 33 | char buf4[100]; 34 | fscanf(fp,"%s\n%s\n%s\n%s",buf1,buf2,buf3,buf4); 35 | fclose(fp); 36 | 37 | string username = string(buf1); 38 | string password = string(buf2); 39 | string keyword = string(buf3); 40 | string number = string(buf4); 41 | 42 | //Log in to google voice 43 | if(gv.Init()) {cout << "GoogleVoice() failed to initialize. Blaming curl. Dying.\n"; return -1;} 44 | r = gv.Login(username,password); 45 | if((gv.debug&1) || r) printf("gv.Login() returned %d.\n\n", r); 46 | 47 | //Check SMS 48 | string results; 49 | r = gv.CheckSMS(results,number,keyword,true); 50 | //printf("%s\n",results.c_str()); 51 | if(!r && gv.debug) printf("SMS Checked Successfully.\n"); 52 | 53 | //run given command 54 | if(!results.empty()) { 55 | FILE *pf; 56 | pf = popen(results.c_str(),"r"); 57 | 58 | if(!pf) {cout << "Could not open command pipe. Dying\n"; return -1;} 59 | 60 | //Grab data from process execution 61 | char buffer[DATA_SIZE]; 62 | string message = ""; 63 | while(!feof(pf)) { 64 | if(fgets(buffer, DATA_SIZE, pf) != NULL) { 65 | message += string(buffer); 66 | } 67 | } 68 | //printf("%d: %s\n",count,message.c_str()); 69 | 70 | if (pclose(pf) != 0) {cout << "Could not close command pipe. Dying\n"; return -1;} 71 | replace_all(message, "\t", " "); 72 | //Send return SMS 73 | int mLen = message.length(); 74 | if(mLen <= 320) 75 | r = gv.SendSMS(number,message); 76 | else { 77 | //I need to split this into multiple messages 78 | string::iterator it = message.begin(); 79 | int count = 0; 80 | string section = ""; 81 | while(it != message.end()) { 82 | section += *it; 83 | ++it; 84 | ++count; 85 | if(count >= 319) { 86 | r = gv.SendSMS(number, section); 87 | count = 0; 88 | section.clear(); 89 | } 90 | } 91 | r = gv.SendSMS(number, section); 92 | } 93 | if((gv.debug&2) || r) printf("gv.SendSMS() returned %d.\n\n", r); 94 | if(gv.debug&1 && !r) printf("SMS send successfully.\n"); 95 | } 96 | return r; 97 | } 98 | 99 | -------------------------------------------------------------------------------- /Youtube/ytb.js: -------------------------------------------------------------------------------- 1 | // YouTube Launcher 2 | // Steven Hickson 3 | // 2013-06-07 4 | // Copyright (c) 2013 5 | // Released under the GPL license 6 | // http://www.gnu.org/copyleft/gpl.html 7 | // Modified version of BlockFlash2 by varanasi,Andrew Pennebaker,Jos van den Oever 8 | // Modified to work with omxplayer and not use flash at all 9 | // -------------------------------------------------------------------- 10 | // 11 | // ==UserScript== 12 | // @name YouTube Launcher 13 | // @namespace None 14 | // @description Plays youtube videos with omxplayer 15 | // @include * 16 | // @exclude http*://youtube.com/* 17 | // @exclude http*://*.youtube.com/* 18 | // @exclude http*://youtube-nocookie.com/* 19 | // @exclude http*://*.youtube-nocookie.com/* 20 | // 21 | // ==/UserScript== 22 | 23 | var ytbody = document.getElementsByTagName('body')[0]; 24 | var ytdiv = document.createElement('div'); 25 | var ythref = location.href; 26 | ythref=ythref.replace('https://','ytb://'); 27 | ythref=ythref.replace('http://','ytb://'); 28 | ytdiv.innerHTML = 'OMXPlayer |>'; 29 | ytdiv.style.backgroundColor = '#f3f3f3'; 30 | ytdiv.style.border='1px solid black'; 31 | ytdiv.style.position = 'fixed'; 32 | ytdiv.style.top = '10px'; 33 | ytdiv.style.left = '10px'; 34 | ytbody.appendChild(ytdiv); 35 | 36 | /* 37 | xpath("//embed").forEach(function(embed) { // put all embed objects in array and check each 38 | if (embed.parentNode.nodeName != "OBJECT" && embed.parentNode.style.display != "none"){ // handle embeds within objects as objects 39 | if(checkforflash(embed)){add_play_flash_div(embed)}; 40 | }; 41 | }); 42 | 43 | xpath("//object").forEach(function(object) { 44 | if(checkforflash(object)){add_play_flash_div(object)}; 45 | }); 46 | 47 | function checkforflash(potl_item){ // checks the element passed to it for Flash content 48 | if (potl_item.hasAttribute("flashvars") ){ 49 | return true 50 | }; 51 | if (potl_item.hasAttribute("type") && potl_item.getAttribute("type").match(/flash|shockwave/)){ 52 | return true 53 | }; 54 | if (potl_item.hasAttribute("src") && potl_item.getAttribute("src").match(/.swf|shockwave|flash|eyewonder/)){ 55 | return true 56 | }; 57 | if (potl_item.innerHTML.match(/.swf|shockwave|flash|eyewonder/)) { 58 | return true 59 | }; 60 | return false; 61 | }; 62 | 63 | function add_play_flash_div(flash){ // places the button-like div before the flash node 64 | var placeholder=document.createElement("a"); 65 | savedDisplay = flash.style.display; 66 | placeholder.setAttribute("class", "ReplaceVideo"); 67 | flash.parentNode.insertBefore(placeholder, flash); 68 | flash.style.display='none'; 69 | flash.on=false; 70 | flash.remove(); 71 | placeholder.style.cursor='pointer'; 72 | placeholder.style.background='green'; 73 | placeholder.style.textAlign='center'; 74 | placeholder.style.textTransform='capitalize'; 75 | placeholder.style.color='black'; 76 | placeholder.innerHTML="[Play Video]"; 77 | var tmp=document.location.href; 78 | tmp=tmp.replace("https","ytb"); 79 | placeholder.href=tmp.replace("http","ytb"); 80 | return true; 81 | } 82 | 83 | function xpath (p, context) { 84 | if (!context) context = document; 85 | var i, arr = [], xpr = document.evaluate(p, context, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null); 86 | for (i = 0; item = xpr.snapshotItem(i); i++) arr.push(item); 87 | return arr; 88 | }; 89 | */ 90 | -------------------------------------------------------------------------------- /TextCommand/gvapi.8: -------------------------------------------------------------------------------- 1 | .\" Manpage for gvapi. 2 | .\" Contact me@stevenhickson to add input or correct errors or typos. 3 | .TH man 8 "23 May 2013" "2.0" "gvapi man page" 4 | .SH NAME 5 | gvapi \- Use of Google voice API in order to send and receive SMS 6 | .SH SYNOPSIS 7 | .I "gvapi [OPTIONS]..." 8 | .SH DESCRIPTION 9 | gvapi was compiled for use with home automation on the Raspberry Pi but will work on any linux system with an internet connection. It uses curl and boost regex in order to login and stores the cookie in /dev/shm. It only logs in once every 24 hours to save time. It supports a multitude of different options and parameters. 10 | For help/comments/questions, feel free to e-mail me at me@stevenhickson.com. I answer sporadically but do eventually respond. 11 | .PP 12 | .SH OPTIONS 13 | .TP 14 | .I "-?" 15 | Same as -h 16 | 17 | .TP 18 | .I "-c" 19 | Checks your incoming text messages to see if you have anything unread. It will mark it whatever it outputs as read unless you also use the -r flag. If you include a number with the -n flag, you can specify it to only check messages received from that number. You can also use the -k flag to specify that the message must start with a certain keyword. 20 | 21 | .TP 22 | .I "-d" 23 | Sets debug mode on. You can also specify debug mode from 1 - 3, where 3 is the most verbose. 24 | .br 25 | .I " Ex: gvapi -c -d2" 26 | 27 | .TP 28 | .I "-h" 29 | Asks for some quick general use help for gvapi. 30 | 31 | .TP 32 | .I "-i" 33 | Outputs the contacts of your google voice account in the form name==number 34 | 35 | .TP 36 | .I "-k KEYWORD" 37 | Sets a keyword that has to be in the beginning of the text message for it to be returned. This is useful as a password for parsing only certain messages. 38 | 39 | .TP 40 | .I "-m MESSAGE" 41 | Sends the message you specify. This should be in quotes if it contains special characters or a space. The number also has to be specified otherwise it won't have a message to send 42 | .br 43 | .I " Ex: gvapi -n +15551234 -m Hello" 44 | 45 | .TP 46 | .I "-n NUMBER" 47 | Can be used with the -c flag to check messages from a certain number or the -m flag to send a message. Can be in a format without the country code, with just the country code, or with a plus sign and the country code. If the foremost, it interprets it as a US number. 48 | .br 49 | .I " Ex: gvapi -n 5551234 -c" 50 | 51 | .TP 52 | .I "-p PASSWORD" 53 | Can be used with the -u flag to log in manually. If not specified, the program uses the default username and password specified in ~/.gv 54 | 55 | .TP 56 | .I "-r" 57 | Receives and deletes SMS messges. Can be used with the -c flag or without. It is the same as the -c flag but instead of just marking the messages as read. It deletes them. 58 | 59 | .TP 60 | .I "-u USERNAME" 61 | Can be used with the -p flag to log in manually. See the -p flag for more details. Cannot be used without the -p flag. 62 | 63 | .TP 64 | .I "-v" 65 | Outputs version and creater information 66 | 67 | .SH AUTHOR 68 | .I "Steven Hickson (me@stevenhickson.com)" 69 | .SH BUGS 70 | No known bugs. To report bugs, send a clear description to me@stevenhickson.com 71 | Since this program is fairly crude, user typos could cause crashes/failed responses. Please read the man page thoroughly before submitting a bug. 72 | .SH COPYRIGHT 73 | Copyright © 2013 Steven Hickson. License GPLv3+: GNU GPL version 3 or later . 74 | This is free software: you are free to change and redistribute it as long as you give credit to the author and include this license. There is NO WARRANTY, to the extent permitted by law. 75 | .SH HISTORY 76 | This is the second major version of this program 77 | .SH SEE ALSO 78 | http://stevenhickson.blogspot.com/ 79 | -------------------------------------------------------------------------------- /Youtube/yt.js: -------------------------------------------------------------------------------- 1 | // YouTube Launcher 2 | // Steven Hickson 3 | // 2013-06-07 4 | // Copyright (c) 2013 5 | // Released under the GPL license 6 | // http://www.gnu.org/copyleft/gpl.html 7 | // Modified version of BlockFlash2 by varanasi,Andrew Pennebaker,Jos van den Oever 8 | // Modified to work with omxplayer and not use flash at all 9 | // -------------------------------------------------------------------- 10 | // 11 | // ==UserScript== 12 | // @name YouTube Launcher 13 | // @namespace None 14 | // @description Plays youtube videos with omxplayer 15 | // @include http*://youtube.com/* 16 | // @include http*://*.youtube.com/* 17 | // @include http*://youtube-nocookie.com/* 18 | // @include http*://*.youtube-nocookie.com/* 19 | // 20 | // ==/UserScript== 21 | 22 | var ytbody = document.getElementsByTagName('body')[0]; 23 | var ytdiv = document.createElement('div'); 24 | var ythref = location.href; 25 | ythref=ythref.replace('https://','yt://'); 26 | ythref=ythref.replace('http://','yt://'); 27 | ytdiv.innerHTML = 'OMXPlayer |>'; 28 | ytdiv.style.backgroundColor = '#f3f3f3'; 29 | ytdiv.style.border='1px solid black'; 30 | ytdiv.style.position = 'fixed'; 31 | ytdiv.style.top = '10px'; 32 | ytdiv.style.left = '10px'; 33 | ytbody.appendChild(ytdiv); 34 | 35 | 36 | /*xpath("//embed").forEach(function(embed) { // put all embed objects in array and check each 37 | if (embed.parentNode.nodeName != "OBJECT" && embed.parentNode.style.display != "none"){ // handle embeds within objects as objects 38 | if(checkforflash(embed)){add_play_flash_div(embed)}; 39 | }; 40 | }); 41 | 42 | xpath("//object").forEach(function(object) { 43 | if(checkforflash(object)){add_play_flash_div(object)}; 44 | }); 45 | */ 46 | /* 47 | function checkforflash(potl_item){ // checks the element passed to it for Flash content 48 | if (potl_item.hasAttribute("flashvars") ){ 49 | return true 50 | }; 51 | if (potl_item.hasAttribute("type") && potl_item.getAttribute("type").match(/flash|shockwave/)){ 52 | return true 53 | }; 54 | if (potl_item.hasAttribute("src") && potl_item.getAttribute("src").match(/.swf|shockwave|flash|eyewonder/)){ 55 | return true 56 | }; 57 | if (potl_item.innerHTML.match(/.swf|shockwave|flash|eyewonder/)) { 58 | return true 59 | }; 60 | if (potl_item.hasAttribute("class") && potl_item.getAtrribute("class").match(/ytp/)){ 61 | return true 62 | }; 63 | return false; 64 | }; 65 | 66 | function add_play_flash_div(flash){ // places the button-like div before the flash node 67 | var ytbody = document.getElementsByTagName('body')[0]; 68 | var ytdiv = document.createElement('div'); 69 | var ythref = location.href; 70 | ythref=ythref.replace('https://','yt://'); 71 | ythref=ythref.replace('http://','yt://'); 72 | ytdiv.innerHTML = 'OMX |>'; 73 | ytdiv.style.backgroundColor = '#f3f3f3'; 74 | ytdiv.style.border='1px solid black'; 75 | ytdiv.style.position = 'fixed'; 76 | ytdiv.style.top = '10px'; 77 | ytdiv.style.left = '10px'; 78 | ytbody.appendChild(ytdiv); 79 | flash.remove(); 80 | return true; 81 | } 82 | 83 | all_objects = document.getElementsByTagName('object'); 84 | all_embeds = document.getElementsByTagName('embed'); 85 | all_divs = document.getElementsByTagName('div'); 86 | 87 | for (var i = 0; i < all_ojects.length; i++) { 88 | if(checkforflash(all_objects[i]) { 89 | add_play_flash_div(all_objects[i]); 90 | } 91 | } 92 | 93 | for (var i = 0; i < all_embeds.length; i++) { 94 | if(checkforflash(all_embeds[i]) { 95 | add_play_flash_div(all_embeds[i]); 96 | } 97 | } 98 | 99 | for (var i = 0; i < all_divs.length; i++) { 100 | if(checkforflash(all_divs[i]) { 101 | add_play_flash_div(all_divs[i]); 102 | } 103 | } 104 | */ 105 | -------------------------------------------------------------------------------- /Youtube/youtube-safe: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [ $# -ne 1 ] && [ $# -ne 2 ] 3 | then 4 | echo "Usage : $0 " 5 | echo "e.g : $0 http://www.youtube.com/watch?v=D1R-jKKp3NA" 6 | else 7 | #Some safety so we don't run this a bajillion times 8 | omx=`pgrep omxplayer | wc -l` 9 | yt=`pgrep youtube | wc -l` 10 | ytsearch=`pgrep youtube-search | wc -l` 11 | yt=$((yt - ytsearch)) 12 | if [[ "$omx" -gt 0 ]] || [[ $yt -gt 2 ]] ; then 13 | exit 0 14 | fi 15 | if [ -z $DISPLAY ] ; then 16 | run_command="omxplayer -r -o hdmi" 17 | else 18 | run_command="xterm -fullscreen -bg black -fg black -e omxplayer -r -o hdmi" 19 | fi 20 | 21 | #check to see if fifo exists (if this is really big, I'll have to move it out of /dev/shm. 22 | BUFFER_TIME=5 23 | 24 | #check where shm is located 25 | if [ -d "/run/shm" ]; then 26 | STREAM_FIFO="/run/shm/temp.stream" 27 | else 28 | STREAM_FIFO="/dev/shm/temp.stream" 29 | fi 30 | 31 | if [ ! -e $STREAM_FIFO ]; then 32 | mkfifo $STREAM_FIFO 33 | fi 34 | 35 | var=$1 36 | 37 | #check to see if we should use get_flash_videos instead 38 | other=`echo "$var" | grep "hulu\|vimeo" | wc -l` 39 | if [[ "$other" -eq 0 ]] ; then 40 | http=`echo "$var" | grep "http\|ytb" | wc -l` 41 | if [[ "$http" -eq 0 ]] ; then 42 | count=`echo "$var" | wc -l` 43 | num=1 44 | while [ $num -le $count ] ; 45 | do 46 | video=`echo "$var" | head -n $num | tail -n 1` 47 | if [[ "$video" == yt* ]] ; then 48 | video="${video/yt/http}" 49 | fi 50 | todnload=`youtube-dl -i -g --cookies /dev/shm/youtube_cookie.txt "$video"` 51 | wget -O "$STREAM_FIFO" "$todnload" & 1>/dev/null 2>/dev/null 52 | sleep $BUFFER_TIME 53 | $run_command "$STREAM_FIFO" 54 | num=`expr $num + 1` 55 | done 56 | else 57 | list=`echo "$var" | grep list | wc -l` 58 | if [[ list -eq 0 ]] ; then 59 | if [[ "$var" == yt* ]] ; then 60 | var="${var/yt/http}" 61 | fi 62 | todnload=`youtube-dl -i -g --cookies /dev/shm/youtube_cookie.txt "$var"` 63 | tot=`echo "$todnload" | wc -l` 64 | num=1 65 | while [ $num -le $tot ] ; 66 | do 67 | echo "$num out of $tot" 68 | link=`echo "$todnload" | head -n $num | tail -n 1` 69 | wget -O "$STREAM_FIFO" "$link" & 1>/dev/null 2>/dev/null 70 | sleep $BUFFER_TIME 71 | $run_command "$STREAM_FIFO" 72 | num=`expr $num + 1` 73 | done 74 | else 75 | echo "Youtube playlist ..." 76 | num=1 77 | if [[ "$var" == yt* ]] ; then 78 | var="${var/yt/http}" 79 | fi 80 | todnload=`youtube-dl -g --cookies /dev/shm/youtube_cookie.txt --playlist-start $num --playlist-end $num "$var"` 81 | while [ "$todnload" != "" ] ; 82 | do 83 | wget -O "$STREAM_FIFO" "$todnload" & 1>/dev/null 2>/dev/null 84 | sleep $BUFFER_TIME 85 | $run_command "$STREAM_FIFO" 86 | num=`expr $num + 1` 87 | if [[ "$var" == yt* ]] ; then 88 | var="${var/yt/http}" 89 | fi 90 | todnload=`youtube-dl -g --cookies /dev/shm/youtube_cookie.txt --playlist-start $num --playlist-end $num "$var"` 91 | done 92 | fi 93 | fi 94 | else 95 | echo "Using get_flash_videos" 96 | get_flash_videos -f "$STREAM_FIFO" -q -y "$var" & 1>/dev/null 2>/dev/null 97 | sleep 1 98 | $run_command "$STREAM_FIFO" 99 | fi 100 | rm $STREAM_FIFO 101 | fi 102 | -------------------------------------------------------------------------------- /TextCommand/gvapi.cpp: -------------------------------------------------------------------------------- 1 | // GoogleVoice API. v2.0.1 Steven Hickson 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | //#include 8 | #include "gvoice.h" 9 | 10 | using namespace std; 11 | //using namespace boost; 12 | 13 | void PrintUsage(int verbose=0); 14 | 15 | int main(int argc, char *argv[]) 16 | { 17 | GoogleVoice gv; 18 | int a,d,r; 19 | bool check_sms = false, send_sms = false, delete_sms = false, contact_info = false; 20 | string keyword=""; 21 | string an,am; 22 | string au,ap; 23 | 24 | bool config = true; 25 | 26 | while((a=getopt(argc,argv, "d::h?vu:p:irck:n:m:")) != -1) 27 | { 28 | switch(a) 29 | { 30 | case 'i': 31 | contact_info = true; 32 | break; 33 | case 'd': // debug mode. 34 | if(optarg) d=atoi(optarg); else d=1; 35 | printf("Debugging level %d enabled\n",d); 36 | gv.debug=d; 37 | break; 38 | case 'u': // username 39 | config=false; 40 | au=optarg; 41 | break; 42 | case 'p': // password 43 | ap=optarg; 44 | break; 45 | case 'n': // number 46 | an=optarg; 47 | break; 48 | case 'm': // message 49 | am=optarg; 50 | send_sms = true; 51 | break; 52 | case 'r': // receive messages (delete) 53 | check_sms = true; 54 | delete_sms = true; 55 | break; 56 | case 'c': // check messages (mark as read) 57 | check_sms = true; 58 | break; 59 | case 'k': // keyword for checking messages 60 | keyword = optarg; 61 | break; 62 | case '?': 63 | case 'h': // help 64 | PrintUsage(1); return 0; 65 | case 'v': // version. 66 | printf("GoogleVoice API by Steven Hickson. %s. https://github.com/StevenHickson/PiAUISuite\n\n", "2.0"); 67 | return 0; 68 | } 69 | } 70 | if((send_sms && an.empty()) || (!keyword.empty() && !check_sms) || (delete_sms && !check_sms) || (ap.empty() ^ au.empty())) { 71 | printf("Error, improper flag combination\n"); 72 | PrintUsage(1); 73 | } 74 | 75 | if(gv.Init()) {cout << "GoogleVoice() failed to initialize. Blaming curl. Dying.\n"; return -1;} 76 | 77 | //Let's fill in the config options if they weren't specified 78 | if(config) { 79 | FILE *fp; 80 | char *passPath; 81 | passPath = getenv("HOME"); 82 | if(passPath == NULL) { 83 | printf("Could not get $HOME\n"); 84 | return -1; 85 | } 86 | string path = string(passPath); 87 | path += "/.gv"; 88 | fp = fopen(path.c_str(),"r"); 89 | if(!fp) {cout << "Couldn't open password file. Dying\n"; return -1;} 90 | char buf1[100]; 91 | char buf2[100]; 92 | fscanf(fp,"%s\n%s\n",buf1,buf2); 93 | fclose(fp); 94 | au = string(buf1); 95 | ap = string(buf2); 96 | } 97 | 98 | r = gv.Login(au,ap); 99 | if((gv.debug&1) || r) printf("gv.Login() returned %d.\n\n", r); 100 | 101 | if(contact_info) { 102 | gv.GetContactInfo(); 103 | } else if(check_sms) { 104 | string results; 105 | string number = ""; 106 | if(!an.empty()) 107 | number += an; 108 | r = gv.CheckSMS(results,number,keyword,delete_sms); 109 | printf("%s\n",results.c_str()); 110 | if(!r && gv.debug) printf("SMS Checked Successfully.\n"); 111 | } else { 112 | r = gv.SendSMS(an,am); 113 | if((gv.debug&2) || r) printf("gv.SendSMS() returned %d.\n\n", r); 114 | if(!r) printf("SMS sent successfully.\n"); 115 | } 116 | 117 | return r; 118 | } 119 | 120 | void PrintUsage(int verbose) 121 | { 122 | printf("Usage: %s -hdicr -u [username] -p [password] -k [keyword] -n [number] -m [textmsg]\n", "gvapi"); //argv[0]); 123 | if(!verbose) return; 124 | printf("\t-d{n}:\t\tSet debug (verboseness). If debug value {n} not specified, defaults to 1.\n\t\t\tdebug bits: 1=output GV calls. 2=dump GV call results.\n"); 125 | printf("For more help, type man gvapi into your shell\n"); 126 | } 127 | 128 | -------------------------------------------------------------------------------- /Imaging/tracking.cpp: -------------------------------------------------------------------------------- 1 | #include "opencv/cv.h" 2 | #include "opencv2/highgui/highgui.hpp" 3 | #include "opencv2/objdetect/objdetect.hpp" 4 | #include "opencv2/imgproc/imgproc.hpp" 5 | #include 6 | #include 7 | 8 | using namespace cv; 9 | using namespace std; 10 | 11 | #define _USE_MATH_DEFINES 12 | #define THRESH 0.4f 13 | 14 | //local #defines 15 | #define B_MEAN 99.1442f 16 | #define R_MEAN 138.0654f 17 | #define PI 3.141592653589793238462643383279502884f 18 | 19 | //this is actually the inverse of the covariance matrix 20 | #define COV_11 0.00376353477484179f //552.6847 21 | #define COV_12 -0.00330727927436376f //326.5669 22 | #define COV_21 -0.00330727927436376f //326.5669 23 | #define COV_22 0.00559726810338469f //371.6184 24 | 25 | #define COV_DET 9.87418612943281e+04 26 | 27 | #define WINDOW_NAME "Webcam" 28 | 29 | inline void SkinSegment1(IplImage *frame, CvMemStorage *pStorage); 30 | inline void SkinSegment2(IplImage *frame, Mat &kernel, CvMemStorage *pStorage); 31 | 32 | int main( int argc, char** argv ) { 33 | cvNamedWindow( WINDOW_NAME, CV_WINDOW_NORMAL); 34 | 35 | CvCapture* capture = cvCreateCameraCapture(0) ; 36 | IplImage* frame; 37 | CvMemStorage* pStorage = cvCreateMemStorage(0); 38 | 39 | float data[9] = {0.111111111f,0.111111111f,0.111111111f,0.111111111f,0.111111111f,0.111111111f,0.111111111f,0.111111111f,0.111111111f}; 40 | Mat kernel = Mat(3, 3, CV_32FC1, &data); 41 | //Mat kernel2 = (cv::Mat_(3,3) << 0, 1, 0, 0, 1, 0, 0, 1, 0); 42 | 43 | int args = 0; 44 | if(argc > 1) { 45 | if(atoi(argv[1]) == 1) 46 | args = 1; 47 | else if(atoi(argv[1]) == 2) 48 | args = 2; 49 | } 50 | 51 | while(1) { 52 | frame = cvQueryFrame( capture ); 53 | if( !frame ) break; 54 | 55 | if(args == 1) { 56 | SkinSegment1(frame,pStorage); 57 | } else 58 | SkinSegment2(frame,kernel,pStorage); 59 | char c = cvWaitKey(33); 60 | if( c == 27 ) break; 61 | 62 | } 63 | cvReleaseCapture( &capture ); 64 | cvDestroyWindow( "Webcam" ); 65 | } 66 | 67 | inline void SkinSegment1(IplImage *frame, CvMemStorage *pStorage) { 68 | Mat hsv,bw,tmp; 69 | Mat src(frame); 70 | cvtColor(src, hsv, CV_BGR2HSV); 71 | inRange(hsv, Scalar(0, 10, 60), Scalar(20, 150, 255), bw); 72 | erode(bw,tmp,Mat()); 73 | //dilate(tmp,bw,Mat()); 74 | IplImage copy = tmp; 75 | cvShowImage( WINDOW_NAME, ©); 76 | } 77 | 78 | inline void SkinSegment2(IplImage *frame, Mat& kernel, CvMemStorage *pStorage) { 79 | uint8_t* pixelPtr = (uint8_t*)frame->imageData; 80 | char r,g,b; 81 | float cr,cb,tmp; 82 | Mat conv(frame->height, frame->width, CV_32FC1); 83 | float *convPtr = (float *)conv.data; 84 | float *convEnd = (float *)conv.dataend; 85 | Mat filter, final; 86 | while( convPtr < convEnd ) { 87 | //r = pixelPtr[i*frame->widthStep*cn + j*cn + 0]; 88 | r = *pixelPtr; 89 | ++pixelPtr; 90 | g = *pixelPtr; 91 | ++pixelPtr; 92 | b = *pixelPtr; 93 | ++pixelPtr; 94 | //convert from rgb to ycbcr and subtract mean, ignore y, taken from wikipedia page on ycbcr 95 | cb = -0.16874f * r - 0.33126f * g + 0.50000f * b + 128.0f - B_MEAN; 96 | cr = 0.50000f * r - 0.41869f * g - 0.08131f * b + 128.0f - R_MEAN; 97 | //matrix multiplication [cr , cb] * inv(cov) * [cr ; cb] 98 | tmp = cr * (COV_11 * cr + COV_21 * cb) + cb * (COV_12 * cr + COV_22 * cb); 99 | *convPtr = float(exp(-0.5f * tmp) / (2.0f*PI*pow(COV_DET,5.0e-1))); 100 | ++convPtr; 101 | } 102 | filter2D(conv,filter,-1,kernel,cvPoint(-1,-1),0.0f,BORDER_DEFAULT); 103 | float *filterPtr = (float *)filter.data; 104 | float *filterEnd = (float *)filter.dataend; 105 | float *max = max_element(filterPtr,filterEnd); 106 | //printf("%f\n",*max); 107 | while( filterPtr < filterEnd ) { 108 | *filterPtr = (*filterPtr / *max); 109 | ++filterPtr; 110 | } 111 | threshold(filter,final,THRESH,1,THRESH_BINARY); 112 | dilate(final,filter,Mat()); 113 | IplImage copy = filter; 114 | cvShowImage( WINDOW_NAME, ©); 115 | } -------------------------------------------------------------------------------- /Youtube/youtube-search.cpp: -------------------------------------------------------------------------------- 1 | // Youtube Script Created Steven Hickson 2 | #define VERSION "v1.0.1" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "youtube-search.h" 8 | 9 | using namespace std; 10 | using namespace boost; 11 | 12 | void PrintUsage(void); 13 | 14 | int main(int argc, char *argv[]) { 15 | Youtube tube; 16 | 17 | if(argc < 2) { 18 | PrintUsage(); 19 | return -1; 20 | } 21 | 22 | tube.debug = 1; 23 | 24 | string search = ""; 25 | for(int i = 1; i < argc; ++i) { 26 | if(i != 1) 27 | search += "+"; 28 | search += string(argv[i]); 29 | } 30 | if (tube.Init()) { 31 | cout << "Curl failed to initialize. Dying.\n"; 32 | return -1; 33 | } 34 | string link; 35 | tube.Search(search, &link, true); 36 | tube.PlayVideo(link, true); 37 | return 0; 38 | } 39 | 40 | void PrintUsage(void) { 41 | printf("Just type what you want it to search just like on the website.\nEx: youtube-search Somebody that I used to know\n"); 42 | printf("Copyright GPL v3 Steven Hickson 2013\n"); 43 | } 44 | 45 | Youtube::Youtube() { 46 | hcurl = NULL; 47 | debug = 0; 48 | version = VERSION; 49 | } 50 | 51 | Youtube::~Youtube() { 52 | if (hcurl) curl_easy_cleanup(hcurl); 53 | } 54 | 55 | //Searches for 1st download link on piratebay.gl 56 | 57 | int Youtube::Search(string query, string *link, bool verify) { 58 | if(!init) 59 | Init(); 60 | //technically this should never happen now. 61 | if (!hcurl) { 62 | cout << "hcurl is NULL. Did you forget to call Init()?\n"; 63 | return -1; 64 | } 65 | 66 | string search = "http://www.youtube.com/results?search_query="; 67 | search += query; 68 | curl_easy_setopt(hcurl, CURLOPT_URL, search.c_str()); 69 | curlbuf.clear(); 70 | cr = curl_easy_perform(hcurl); 71 | if (cr != CURLE_OK) { 72 | cout << "curl() error on getting link: " << errorbuf << endl; 73 | return -3; 74 | } 75 | 76 | if (debug & 2) cout << "\nLink curlbuf: [" << curlbuf << "]\n"; 77 | 78 | regex rexp("\"/watch\\?([a-z0-9A-Z=]+)\" class"); cmatch m; 79 | if (regex_search(curlbuf.c_str(), m, rexp)) { 80 | string t = "http://youtube.com/watch?"; 81 | t += string(m[1]); 82 | if (verify) 83 | printf("%s\n", t.c_str()); 84 | *link = t; 85 | return 0; 86 | } else { 87 | cout << "Could not find video. Try again.\n"; 88 | return -1; 89 | } 90 | 91 | return 0; 92 | } 93 | 94 | int Youtube::PlayVideo(string video, bool verify) { 95 | if(!init) 96 | Init(); 97 | FILE *pf; 98 | //This seems like a lot of space to use to format the string but it keeps it well organized for me 99 | string command = "youtube-safe "; 100 | command += "\""; 101 | command += video; 102 | command += "\""; 103 | if(verify) printf("%s\n",command.c_str()); 104 | pf = popen(command.c_str(), "r"); 105 | 106 | if (!pf) { 107 | cout << "Could not open command pipe. Dying\n"; 108 | return -1; 109 | } 110 | 111 | //Grab data from process execution 112 | char buffer[DATA_SIZE]; 113 | string message = ""; 114 | while (!feof(pf)) { 115 | if (fgets(buffer, DATA_SIZE, pf) != NULL) { 116 | message += string(buffer); 117 | } 118 | } 119 | printf("%s\n",message.c_str()); 120 | 121 | if (pclose(pf) != 0) { 122 | cout << "Could not close command pipe. Dying\n"; 123 | return -1; 124 | } 125 | 126 | } 127 | 128 | int Youtube::Init(void) { 129 | hcurl = curl_easy_init(); 130 | if (!hcurl) return -1; 131 | curl_easy_setopt(hcurl, CURLOPT_ERRORBUFFER, errorbuf); 132 | curl_easy_setopt(hcurl, CURLOPT_WRITEFUNCTION, CurlWriter); 133 | curl_easy_setopt(hcurl, CURLOPT_WRITEDATA, &curlbuf); 134 | 135 | curl_easy_setopt(hcurl, CURLOPT_HEADER, 0); 136 | curl_easy_setopt(hcurl, CURLOPT_FOLLOWLOCATION, 1); 137 | curl_easy_setopt(hcurl, CURLOPT_USERAGENT, "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.8) Gecko/20100804 Gentoo Firefox/3.6.8"); 138 | init = true; 139 | //curl_easy_setopt(hcurl, CURLOPT_COOKIEJAR, "cookie.txt"); 140 | return 0; 141 | } 142 | 143 | int Youtube::CurlWriter(char *data, size_t size, size_t nmemb, string *buffer) { 144 | if (buffer != NULL) { 145 | buffer->append(data, size * nmemb); 146 | return size*nmemb; 147 | } 148 | return 0; 149 | } 150 | 151 | -------------------------------------------------------------------------------- /DownloadController/downconn.cpp: -------------------------------------------------------------------------------- 1 | // Downloader Script Created Steven Hickson 2 | #define VERSION "v1.0.1" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "downconn.h" 8 | 9 | using namespace std; 10 | using namespace boost; 11 | 12 | Downloader::Downloader() { 13 | hcurl = NULL; 14 | debug = 0; 15 | version = VERSION; 16 | } 17 | 18 | Downloader::~Downloader() { 19 | if (hcurl) curl_easy_cleanup(hcurl); 20 | } 21 | 22 | //Searches for 1st download link on thepiratebay.s 23 | 24 | int Downloader::Search(string download, string *link, bool verify) { 25 | if(!init) 26 | Init(); 27 | //technically this should never happen now. 28 | if (!hcurl) { 29 | cout << "hcurl is NULL. Did you forget to call Init()?\n"; 30 | return -1; 31 | } 32 | 33 | //Going back to using https again 34 | string torr = "https://thepiratebay.la/search/"; 35 | torr += download; 36 | torr += "/0/7/0"; 37 | curl_easy_setopt(hcurl, CURLOPT_URL, torr.c_str()); 38 | curlbuf.clear(); 39 | cr = curl_easy_perform(hcurl); 40 | if (cr != CURLE_OK) { 41 | cout << "curl() error on getting link: " << errorbuf << endl; 42 | return -3; 43 | } 44 | 45 | if (debug & 2) cout << "\nLink curlbuf: [" << curlbuf << "]\n"; 46 | 47 | regex rexp("append(data, size * nmemb); 155 | return size*nmemb; 156 | } 157 | return 0; 158 | } 159 | 160 | -------------------------------------------------------------------------------- /Install/UpdateAUISuite.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | function playvideo() { 4 | if [ -e "/usr/bin/playvideo" ] ; then 5 | echo "Updating playvideo ..." 6 | wget -N -P /usr/bin/ https://raw.github.com/StevenHickson/PiAUISuite/master/PlayVideoScripts/playvideo 7 | chmod +x /usr/bin/playvideo 8 | wget -N -P /usr/share/man/man8/ https://raw.github.com/StevenHickson/PiAUISuite/master/PlayVideoScripts/playvideo.8.gz 9 | fi 10 | } 11 | 12 | function download() { 13 | if [ -e "/usr/bin/download" ] ; then 14 | echo "Updating download ..." 15 | tmp="$ROOT_DIR/DownloadController/" 16 | tmp+="$DIR" 17 | tmp+="download" 18 | wget -N -P /usr/bin/ "$tmp" 19 | chmod +x /usr/bin/download 20 | fi 21 | } 22 | 23 | function gtextcommand() { 24 | if [ -e "/usr/bin/gtextcommand" ] ; then 25 | echo "Updating gtextcommand ..." 26 | tmp="$ROOT_DIR/TextCommand/" 27 | tmp+="$DIR" 28 | tmp+="gtextcommand" 29 | wget -N -P /usr/bin/ "$tmp" 30 | chmod +x /usr/bin/gtextcommand 31 | fi 32 | } 33 | 34 | function gvapi() { 35 | if [ -e "/usr/bin/gvapi" ] ; then 36 | echo "Updating gvapi ..." 37 | tmp="$ROOT_DIR/TextCommand/" 38 | tmp+="$DIR" 39 | tmp+="gvapi" 40 | wget -N -P /usr/bin/ "$tmp" 41 | chmod +x /usr/bin/gvapi 42 | wget -N -P /usr/share/man/man8/ https://raw.github.com/StevenHickson/PiAUISuite/master/TextCommand/gvapi.8.gz 43 | fi 44 | } 45 | 46 | function youtube() { 47 | if [ -e "/usr/bin/youtube" ] ; then 48 | echo "Updating youtube ..." 49 | #wget -N -P /usr/bin/ https://raw.github.com/StevenHickson/PiAUISuite/master/Youtube/youtube 50 | #chmod +x /usr/bin/youtube 51 | wget -N -P /usr/bin/ https://raw.github.com/StevenHickson/PiAUISuite/master/Youtube/youtube-safe 52 | chmod +x /usr/bin/youtube-safe 53 | ln -s /usr/bin/youtube-safe /usr/bin/youtube 54 | wget -N -P /usr/bin/ https://raw.github.com/StevenHickson/PiAUISuite/master/Youtube/youtube-dlfast 55 | chmod +x /usr/bin/youtube-dlfast 56 | wget -N -P /etc/cron.daily/ https://raw.github.com/StevenHickson/PiAUISuite/master/Youtube/update-youtubedl 57 | chmod +x /etc/cron.daily/update-youtubedl 58 | tmp="$ROOT_DIR/Youtube/" 59 | tmp+="$DIR" 60 | tmp+="youtube-search" 61 | wget -N -P /usr/bin/ "$tmp" 62 | chmod +x /usr/bin/youtube-search 63 | wget -N -P /usr/share/applications/ https://raw.github.com/StevenHickson/PiAUISuite/master/Youtube/yt.desktop 64 | wget -N -P /usr/share/applications/ https://raw.github.com/StevenHickson/PiAUISuite/master/Youtube/ytb.desktop 65 | mkdir -p "$USER_HOME/.local/share/midori/scripts" 66 | wget -N -P "$USER_HOME/.local/share/midori/scripts/" https://raw.github.com/StevenHickson/PiAUISuite/master/Youtube/yt.js 67 | wget -N -P "$USER_HOME/.local/share/midori/scripts/" https://raw.github.com/StevenHickson/PiAUISuite/master/Youtube/ytb.js 68 | update-desktop-database 69 | youtube-dl -U 70 | fi 71 | } 72 | 73 | function voicecommand() { 74 | if [ -e "/usr/bin/voicecommand" ] ; then 75 | echo "Updating voicecommand ..." 76 | tmp="$ROOT_DIR/VoiceCommand/" 77 | tmp+="$DIR" 78 | tmp+="voicecommand" 79 | wget -N -P /usr/bin/ "$tmp" 80 | chmod +x /usr/bin/voicecommand 81 | wget -N -P /usr/bin/ https://raw.github.com/StevenHickson/PiAUISuite/master/VoiceCommand/google 82 | chmod +x /usr/bin/google 83 | wget -N -P /usr/bin/ https://raw.github.com/StevenHickson/PiAUISuite/master/VoiceCommand/tts 84 | chmod +x /usr/bin/tts 85 | wget -N -P /usr/bin/ https://raw.github.com/StevenHickson/PiAUISuite/master/VoiceCommand/speech-recog.sh 86 | chmod +x /usr/bin/speech-recog.sh 87 | wget -N -P /usr/share/man/man8/ https://raw.github.com/StevenHickson/PiAUISuite/master/VoiceCommand/voicecommand.8.gz 88 | fi 89 | } 90 | 91 | # Make sure only root can run our script 92 | if [ "$(id -u)" != "0" ]; then 93 | echo "This script must be run as root" 1>&2 94 | exit 1 95 | fi 96 | 97 | #Get architecture 98 | ARCH=`uname -m` 99 | if [ "$ARCH" == "armv6l" ] ; then 100 | DIR="" 101 | elif [ "$ARCH" == "x86" ] ; then 102 | DIR="x86/" 103 | elif [ "$ARCH" == "x86_64" ] ; then 104 | DIR="x64/" 105 | fi 106 | ROOT_DIR="https://raw.github.com/StevenHickson/PiAUISuite/master" 107 | 108 | USER_HOME="/home/${SUDO_USER}" 109 | 110 | #I should first try to update the Update script 111 | wget https://raw.github.com/StevenHickson/PiAUISuite/master/Install/UpdateAUISuite.sh 112 | difference=`diff UpdateAUISuite.sh UpdateAUISuite.sh.1` 113 | 114 | if [ -n "$difference" ] ; then 115 | echo "I found a new version of the update script" 116 | unlink UpdateAUISuite.sh 117 | mv UpdateAUISuite.sh.1 UpdateAUISuite.sh 118 | chmod +x UpdateAUISuite.sh 119 | ./UpdateAUISuite.sh "$1" 120 | exit 121 | else 122 | rm UpdateAUISuite.sh.1 123 | fi 124 | 125 | ARG="$1" 126 | if [ "$ARG" == "playvideo" ] ; then 127 | playvideo 128 | elif [ "$ARG" == "download" ] ; then 129 | download 130 | elif [ "$ARG" == "gtextcommand" ] ; then 131 | gtextcommand 132 | elif [ "$ARG" == "gvapi" ] ; then 133 | gvapi 134 | elif [ "$ARG" == "youtube" ] ; then 135 | youtube 136 | elif [ "$ARG" == "voicecommand" ] ; then 137 | voicecommand 138 | else 139 | playvideo 140 | download 141 | gtextcommand 142 | gvapi 143 | youtube 144 | voicecommand 145 | fi 146 | -------------------------------------------------------------------------------- /Imaging/test.cpp: -------------------------------------------------------------------------------- 1 | #include "opencv/cv.h" 2 | #include "opencv2/highgui/highgui.hpp" 3 | #include "opencv2/objdetect/objdetect.hpp" 4 | #include "opencv2/imgproc/imgproc.hpp" 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace cv; 11 | using namespace std; 12 | 13 | void FindFaces(Mat &frame, CascadeClassifier &cascade, bool show); 14 | float MotionDetection(const Mat &past, const Mat &now, Mat *motion); 15 | 16 | #define WINDOW_NAME "Webcam" 17 | #define THRESH 20 18 | 19 | int main( int argc, char** argv ) { 20 | 21 | int width = 640; 22 | int height = 480; 23 | bool window = true; 24 | 25 | CvCapture* capture = cvCreateCameraCapture(0) ; 26 | 27 | Mat frame, oldFrame, motion; 28 | CascadeClassifier face_cascade; 29 | if( !face_cascade.load( "face.xml" ) ){ printf("--(!)Error loading\n"); return -1; }; 30 | 31 | int args = 0; 32 | if(argc > 4) { 33 | args = atoi(argv[1]); 34 | window = bool(atoi(argv[2])); 35 | width = atoi(argv[3]); 36 | height = atoi(argv[4]); 37 | } else if(argc > 3) { 38 | args = atoi(argv[1]); 39 | width = atoi(argv[2]); 40 | height = atoi(argv[3]); 41 | } else if(argc > 1) { 42 | if(atoi(argv[1]) == 1) 43 | args = 1; 44 | else if(atoi(argv[1]) == 2) 45 | args = 2; 46 | } 47 | 48 | if(window) 49 | cvNamedWindow( WINDOW_NAME, CV_WINDOW_NORMAL); 50 | 51 | cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_WIDTH, width); 52 | cvSetCaptureProperty(capture, CV_CAP_PROP_FRAME_HEIGHT, height); 53 | 54 | bool firstRun = true; 55 | while(1) { 56 | timeval beg, end; 57 | gettimeofday(&beg, NULL); 58 | if(!firstRun && args == 2) 59 | oldFrame = frame.clone(); 60 | frame = cvQueryFrame( capture ); 61 | if( frame.empty() ) { 62 | cout << "No image for this frame" << endl; 63 | break; 64 | } 65 | 66 | if(args == 1) { 67 | FindFaces(frame,face_cascade,window); 68 | } else if(args == 2) { 69 | if(!firstRun) { 70 | float total = MotionDetection(oldFrame,frame,&motion); 71 | printf("Tot: %f, ",total); 72 | //Here you would check total instead of printing it, and if it is above a certain value, you would save the image 73 | if(window) 74 | imshow( WINDOW_NAME, motion); 75 | } else { 76 | firstRun = false; 77 | motion = frame.clone(); 78 | } 79 | } else if(window) 80 | imshow( WINDOW_NAME, frame ); 81 | gettimeofday(&end, NULL); 82 | double elapsed = (end.tv_sec - beg.tv_sec) + 83 | ((end.tv_usec - beg.tv_usec)/1000000.0); 84 | printf("time: %f\n", elapsed); 85 | char c = cvWaitKey(33); 86 | if( c == 27 ) break; 87 | 88 | } 89 | cvReleaseCapture( &capture ); 90 | if(window) 91 | cvDestroyWindow( "Webcam" ); 92 | } 93 | 94 | void FindFaces(Mat &frame, CascadeClassifier &cascade, bool show) { 95 | //find faces using haar recognition 96 | Mat gray; 97 | cvtColor(frame,gray,CV_BGR2GRAY); 98 | vector faces; 99 | cascade.detectMultiScale( gray, faces, 1.1, 3, 0|CV_HAAR_SCALE_IMAGE, Size(40, 40) ); 100 | 101 | //draw rectangles around the face 102 | for( size_t i = 0; i < faces.size(); i++ ) 103 | cout << "I found a face!" << endl; 104 | 105 | if(show) 106 | imshow( WINDOW_NAME, frame ); 107 | } 108 | 109 | inline int abs(int val) { 110 | if(val < 0) 111 | return val * -1; 112 | else 113 | return val; 114 | } 115 | 116 | //returns total change 117 | float MotionDetection(const Mat &past, const Mat &now, Mat *motion) { 118 | int nl = past.rows; // number of lines 119 | // total number of element per line 120 | int nc = past.cols; 121 | int total = 0; 122 | 123 | const unsigned char *pastData = reinterpret_cast(past.data); 124 | const unsigned char *nowData = reinterpret_cast(now.data); 125 | unsigned char *motionData = reinterpret_cast(motion->data); 126 | for (int i = 0; i < nl; i++) { 127 | for (int j = 0; j < nc; j++) { 128 | // process each pixel --------------------- 129 | int b_diff = abs(pastData[past.step[0]*i + past.step[1] * j + 0] - nowData[now.step[0]*i + now.step[1] * j + 0]); 130 | int g_diff = abs(pastData[past.step[0]*i + past.step[1] * j + 1] - nowData[now.step[0]*i + now.step[1] * j + 1]); 131 | int r_diff = abs(pastData[past.step[0]*i + past.step[1] * j + 2] - nowData[now.step[0]*i + now.step[1] * j + 2]); 132 | if(r_diff > THRESH || g_diff > THRESH || b_diff > THRESH) { 133 | motionData[motion->step[0]*i + motion->step[1] * j + 0] = 255; 134 | motionData[motion->step[0]*i + motion->step[1] * j + 1] = 255; 135 | motionData[motion->step[0]*i + motion->step[1] * j + 2] = 255; 136 | total++; 137 | } else { 138 | motionData[motion->step[0]*i + motion->step[1] * j + 0] = 0; 139 | motionData[motion->step[0]*i + motion->step[1] * j + 1] = 0; 140 | motionData[motion->step[0]*i + motion->step[1] * j + 2] = 0; 141 | } 142 | } 143 | } 144 | return (float(total) / float(nl * nc)); 145 | } 146 | -------------------------------------------------------------------------------- /VoiceCommand/voicecommand.8: -------------------------------------------------------------------------------- 1 | .\" Manpage for playvideo. 2 | .\" Contact help@stevenhickson to add input or correct errors or typos. 3 | .TH man 8 "13 May 2013" "2.0" "voicecommand man page" 4 | .SH NAME 5 | voicecommand \- Listen to user defined strings and run the corresponding command 6 | .SH SYNOPSIS 7 | .I "voicecommand [OPTIONS]..." 8 | .SH DESCRIPTION 9 | voicecommand was developed for the Raspberry Pi but will work on any linux system with a microphone attached. It is a crude program, which uses basic comparisons to determine if your voicecommand fits a format specified in a config file; it it does, it runs the corresponding linux command. It supports auto-completion and variables as well as command verification, a continuous mode, and other options. 10 | For help/comments/questions, feel free to e-mail me at help@stevenhickson.com. I answer sporadically but do eventually respond. 11 | .PP 12 | 13 | .TP 14 | Note: All of the flags that turn something on are off can be reversed and overwritten by following it with a 1 or 0. So for instance if you have !continuous==1 in your config file, you can run voicecommand -c0 to turn continuous off. 15 | 16 | .SH OPTIONS 17 | .TP 18 | .I "?" 19 | Same as -h 20 | 21 | .TP 22 | .I "-b" 23 | Turns off the FILL audio. The purpose of this was because the Raspbery Pi (or mine at least) cuts off the first few seconds of audio. This flag turns that feature off. You should only be concerned with this if you hear FILL before everything it says. 24 | 25 | .TP 26 | .I "-c" 27 | Makes voicecommand run in continuous mode, where it will keep listening over and over again. 28 | 29 | .TP 30 | .I "-d" 31 | Sets the duration for listening to the audio for voice commands 32 | 33 | .TP 34 | .I "-D" 35 | Sets the audio hardware. The default is plughw:1,0 36 | - 37 | .TP 38 | .I "-e" 39 | Edits the voicecommand config file. 40 | .br 41 | The format is voice==command 42 | .br 43 | You can use any character except for newlines or == 44 | .br 45 | If the voice starts with ~, the program looks for the keyword anywhere. Ex: ~weather would pick up on weather or what's the weather 46 | .br 47 | You can use ... at the end of the command to specify that everything after the given keyword should be options to the command. 48 | .br 49 | .I "Ex: play==playvideo ..." 50 | .br 51 | This means that if you say "play Futurama", it will run the command playvideo Futurama 52 | .br 53 | You can use $# (where # is any number 1 to 9) to represent a variable. These should go in order from 1 to 9 54 | .br 55 | .I "Ex: $1 season $2 episode $3==playvideo -s $2 -e $3 $1" 56 | .br 57 | This means if you say game of thrones season 1 episode 2, it will run playvideo with the -s flag as 1, the -e flag as 2, and the main argument as game of thrones, i.e. playvideo -s 1 -e 2 game of thrones 58 | .br 59 | Because of these options, it is important that the arguments range from most strict to least strict. 60 | .br 61 | This means that ~ arguments should probably be at the end. 62 | .br 63 | You can also put comments if the line starts with # and special options if the line starts with a ! 64 | .br 65 | Default options are shown as follows: 66 | .br 67 | .I "!keyword==pi,!verify==1,!continuous==1,!quiet==0,!ignore==0,!thresh==0.7,!maxResponse==-1" 68 | .br 69 | .I "api==BLANK,!filler==FILLER FILL,!response==Yes Sir?,!duration==3,!com_dur==2,!hardware==plughw:1,0,!language==en_us" 70 | .br 71 | Keyword, filler, and response accept strings. verify, continuous, quiet, and ignore except 1 or 0 (true or false respectively). thresh excepts a floating point number. These allow you to set some of the flags as permanent options (If these are set, you can overwrite them with the flag options). 72 | .br 73 | You can set a WolframAlpha API and maxResponse (the number of branches) like !api==XXXXXX-XXXXXXXXXX amd !maxResponse==3 74 | .br 75 | You can now customize the language support for speech recognition and some text to speech with the language flag. Look up your country code and use that. Ex. For US: !language==en_us, for Spain !language==es, for Germany !language==de. 76 | 77 | .TP 78 | .I "-f /my-location/config-file" 79 | This allows you to load a different config file located in a different spot. The default one is in your home directory and is ~/.commands.conf 80 | .br 81 | The config file must be formatted the same way. 82 | 83 | .TP 84 | .I "-h" 85 | Shows this man page. 86 | 87 | .TP 88 | .I "-i" 89 | Sets the ignore mode. When this flag is activated, if a command is not in the config file, nothing happens. The default behavior is to try to find an answer or response to that question and then speak it. This turns off that behavior. 90 | 91 | .TP 92 | .I "-I string" 93 | Sets the forced input mode. This allows you to test it without the microphone or get it to parse typed information. It will not run in continuous mode with this. 94 | 95 | .TP 96 | .I "-k word" 97 | Sets the keyword. The default is pi. If this flag is set, the verify and continuous flags are also set since this is only checked during those two modes. 98 | .br 99 | .I " Ex. voicecommand -c -v -k Jarvis" 100 | 101 | .TP 102 | .I "-l" 103 | Sets the duration for listening to the audio for the command keyword. This is different than the -d flag that listens for the voice commands. 104 | 105 | .TP 106 | .I "-s" 107 | Runs a setup operation that attempts to set all of the config options in the config file so that voicecommand works properly 108 | 109 | .TP 110 | .I "-r word" 111 | Sets the response. The default is "Yes Sir?" (For version 1.0, it was Ready?. If this response is more than one word, it should be put in quotes, otherwise it doesn't need to be 112 | .br 113 | .I " Ex. voicecommand -r Ready?" 114 | 115 | .TP 116 | .I "-t #" 117 | Sets the threshold for volume to determine if the keyword was spoken. This should be a floating point number. The default value is 0.7 which works well with the Logitech C310 camera/mic from about 6 feet away. 118 | .br 119 | .I " Ex. voicecommand -t 1.2" 120 | 121 | .TP 122 | .I "-p" 123 | Sets passthrough mode on so that instead of running the commands, it just prints them. This is going to be used for the XBMC plugin and Android app. 124 | 125 | .TP 126 | .I "-q" 127 | Sets quiet mode on so that voicecommand never speaks through the audio output. It still prints everything but doesn't ever respond. This includes the keyword response. 128 | 129 | .TP 130 | .I "-v" 131 | Makes voicecommand verify the keyword. This only happens in continuous mode so if this flag is set, the continuous flag will be set as well. The default mode is to not verify. When voicecommand hears any sound above the threshold, it says the response then listens for a command. The default keyword is pi. When the verify flag is set, after the threshold is met, voicecommand verifies that the keyword was spoken. 132 | 133 | .SH AUTHOR 134 | .I "Steven Hickson (help@stevenhickson.com)" 135 | .SH BUGS 136 | No known bugs. To report bugs, send a clear description to help@stevenhickson.com 137 | Since this program is fairly crude, user typos could cause crashes/failed responses. Please read the man page thoroughly before submitting a bug. 138 | .SH COPYRIGHT 139 | Copyright © 2013 Steven Hickson. License GPLv3+: GNU GPL version 3 or later . 140 | This is free software: you are free to change and redistribute it as long as you give credit to the author and include this license. There is NO WARRANTY, to the extent permitted by law. 141 | .SH HISTORY 142 | This is the second major version of this program 143 | .SH SEE ALSO 144 | http://stevenhickson.blogspot.com/ 145 | -------------------------------------------------------------------------------- /PlayVideoScripts/playvideo: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set_bool=0 4 | random_bool=0 5 | season_bool=0 6 | episode_bool=0 7 | season_set=0 8 | episode_set=0 9 | play_mult_bool=0 10 | play_first=0 11 | continue_bool=0 12 | continue_set=0 13 | list_bool=0 14 | list_set=0 15 | 16 | if [ -z $DISPLAY ] ; then 17 | run_command="omxplayer -r" 18 | else 19 | echo "Running xterm" 20 | run_command="xterm -fullscreen -bg black -fg black -e omxplayer -r" 21 | fi 22 | 23 | for var in "$@" 24 | do 25 | if [ "$var" == "-h" ] || [ "$var" == "-help" ] || [ "$var" == "--help" ] ; then 26 | man playvideo 27 | elif [ "$var" == "-Set" ] || [ "$var" == "-set" ] ; then 28 | set_bool=1 29 | elif [ $set_bool == 1 ] ; then 30 | #echo "Must run this as root or using sudo to use the set flag!" 31 | echo "Creating locate database (This may take a couple of minutes) ..." 32 | #if [ -z $PLAY_PATH ] ; then 33 | # echo "export PLAY_PATH=$HOME" | sudo tee -a /etc/profile >/dev/null 34 | # `source /etc/profile` 35 | #fi 36 | db_path="$HOME/.media.db" 37 | test_out=`sudo updatedb --localpaths="$var" --output="$db_path"` 38 | if [ -n "$test_out" ] ; then 39 | echo "Found error, attempting to use older format" 40 | sudo updatedb -U "$var" --output="$db_path" 41 | fi 42 | echo "Done creating database, setting up cron update ..." 43 | if [ -e "/etc/cron.daily/updatelocaldb" ] ; then 44 | sudo rm -f "/etc/cron.daily/updatelocaldb" 45 | fi 46 | cronjob="#!/bin/sh 47 | # 48 | # cron script to save a update local database. 49 | # 50 | # Written by Steven Hickson for the playvideo project. 51 | # 52 | updatedb --localpaths=$var --output=$HOME/.media.db" 53 | echo "$cronjob" | sudo tee -a /etc/cron.daily/updatelocaldb >/dev/null 54 | sudo sh -c 'chmod +x /etc/cron.daily/updatelocaldb' 55 | echo "Done setting up!" 56 | set_bool=0 57 | exit 0 58 | elif [ "$var" == "-r" ] || [ "$var" == "-random" ] ; then 59 | random_bool=1 60 | elif [ "$var" == "-c" ] || [ "$var" == "-continue" ] ; then 61 | continue_bool=1 62 | elif [ "$var" == "-l" ] || [ "$var" == "-list" ] ; then 63 | list_bool=1 64 | elif [ "$var" == "-Season" ] || [ "$var" == "-S" ] || [ "$var" == "-season" ] || [ "$var" == "-s" ] ; then 65 | season_bool=1 66 | elif [ "$var" == "-Episode" ] || [ "$var" == "-E" ] || [ "$var" == "-episode" ] || [ "$var" == "-e" ] ; then 67 | episode_bool=1 68 | elif [ $continue_bool == 1 ] ; then 69 | continue_bool=0 70 | continue_set="$var" 71 | elif [ $list_bool == 1 ] ; then 72 | list_bool=0 73 | list_set="$var" 74 | elif [ $season_bool == 1 ] ; then 75 | season_bool=0 76 | season_set="$var" 77 | elif [ $episode_bool == 1 ] ; then 78 | episode_bool=0 79 | episode_set="$var" 80 | elif [ "$var" == "-m" ] || [ "$var" == "-multi" ] ; then 81 | play_mult_bool=1 82 | elif [ "$var" == "-f" ] || [ "$var" == "-first" ] ; then 83 | play_first=1 84 | else 85 | if [ -z $play_string ] ; then 86 | play_string="$var" 87 | else 88 | play_string="$play_string*$var" 89 | fi 90 | fi 91 | done 92 | if [ $continue_set -gt 0 ] && [ $episode_set == 0 ] && [ $play_mult_bool == 0 ] ; then 93 | echo "Error: continue flag requires either the multiple flag or the season and episode flag" 94 | exit 0 95 | fi 96 | if [ $continue_set -gt 0 ] && [ $season_set == 0 ] && [ $play_mult_bool == 0 ] ; then 97 | echo "Error: continue flag requires either the multiple flag or the season and episode flag" 98 | exit 0 99 | fi 100 | if [ $season_set == 0 ] && [ $episode_set == 0 ] ; then 101 | play_file=`locate -i -d ~/.media.db "*$play_string*" | grep ".mp4$\|.avi$\|.mkv$\|.mp3$\|.mov$\|.mpg$\|.flv$\|.m4v$"` 102 | elif [ $episode_set == 0 ] ; then 103 | echo "Finding Season: $season_set" 104 | tmp1=`locate -i -d ~/.media.db "*$play_string*S$season_set[^0-9]*" | grep ".mp4$\|.avi$\|.mkv$\|.mp3$\|.mov$\|.mpg$\|.m4v$"` 105 | tmp2=`locate -i -d ~/.media.db "*$play_string*S0$season_set[^0-9]*" | grep ".mp4$\|.avi$\|.mkv$\|.mp3$\|.mov$\|.mpg$\|.m4v$"` 106 | 107 | play_file="$tmp1$tmp2" 108 | if [ -z "$play_file" ] ; then 109 | play_file=`locate -i -d ~/.media.db "*$play_string*Season*$season_set[^0-9]*" | grep ".mp4$\|.avi$\|.mkv$\|.mp3$\|.mov$\|.mpg$\|.m4v$"` 110 | fi 111 | else 112 | echo "Finding Season: $season_set Episode: $episode_set" 113 | tmp1=`locate -i -d ~/.media.db "*$play_string*S$season_set*E$episode_set[^0-9]*" | grep ".mp4$\|.avi$\|.mkv$\|.mp3$\|.mov$\|.mpg$\|.m4v$"` 114 | x_char="x" 115 | tmp2=`locate -i -d ~/.media.db "*$play_string*$season_set$x_char$episode_set[^0-9]*" | grep ".mp4$\|.avi$\|.mkv$\|.mp3$\|.mov$\|.mpg$\|.m4v$"` 116 | play_file="$tmp1$tmp2" 117 | if [ -z "$play_file" ] ; then 118 | tmp1=`locate -i -d ~/.media.db "*$play_string*S$season_set*E0$episode_set[^0-9]*" | grep ".mp4$\|.avi$\|.mkv$\|.mp3$\|.mov$\|.mpg$\|.m4v$"` 119 | x_char="x0" 120 | tmp2=`locate -i -d ~/.media.db "*$play_string*$season_set$x_char$episode_set[^0-9]*" | grep ".mp4$\|.avi$\|.mkv$\|.mp3$\|.mov$\|.mpg$\|.m4v$"` 121 | play_file="$tmp1$tmp2" 122 | fi 123 | if [ -z "$play_file" ] ; then 124 | tmp1=`locate -i -d ~/.media.db "*$play_string*Season*$season_set*E$episode_set[^0-9]*" | grep ".mp4$\|.avi$\|.mkv$\|.mp3$\|.mov$\|.mpg$\|.m4v$"` 125 | tmp2=`locate -i -d ~/.media.db "*$play_string*Season*$season_set*E0$episode_set[^0-9]*" | grep ".mp4$\|.avi$\|.mkv$\|.mp3$\|.mov$\|.mpg$\|.m4v$"` 126 | play_file="$tmp1$tmp2" 127 | fi 128 | if [ -z "$play_file" ] ; then 129 | tmp1=`locate -i -d ~/.media.db "*$play_string*Season*$season_set*Episode[^0-9]$episode_set[^0-9]*" | grep ".mp4$\|.avi$\|.mkv$\|.mp3$\|.mov$\|.mpg$\|.m4v$"` 130 | tmp2=`locate -i -d ~/.media.db "*$play_string*Season*$season_set*Episode[^0-9]0$episode_set[^0-9]*" | grep ".mp4$\|.avi$\|.mkv$\|.mp3$\|.mov$\|.mpg$\|.m4v$"` 131 | play_file="$tmp1$tmp2" 132 | fi 133 | fi 134 | num_files=`echo "$play_file" | wc -l` 135 | echo "$num_files Results" 136 | if [ $num_files -gt 1 ] ; then 137 | if [ $random_bool == 1 ] ; then 138 | play_file=`echo "$play_file" | shuf --random-source=/dev/urandom` 139 | fi 140 | 141 | if [ $list_set -gt 0 ] ; then 142 | play_file=`echo "$play_file" | head -$list_set` 143 | echo "$play_file" 144 | exit 0 145 | elif [ $play_first == 1 ] ; then 146 | play_file=`echo "$play_file" | head -1` 147 | $run_command "$play_file" 148 | exit 0 149 | elif [ $play_mult_bool == 1 ] ; then 150 | if [ $continue_set -gt 0 ] ; then 151 | total_run=$continue_set 152 | else 153 | total_run=$num_files 154 | fi 155 | for (( i = 1 ; i <= $total_run; i++ )) 156 | do 157 | current_play=`echo "$play_file" | head -"$i" | tail -1` 158 | $run_command "$current_play" 159 | done 160 | exit 0 161 | else 162 | 163 | read -p "Multiple Returns, Displaying all, select the appropriate number to play (press [Enter] to display) ..." 164 | for (( i = 1 ; i <= $num_files; i++ )) 165 | do 166 | current_play=`echo "$play_file" | head -"$i" | tail -1` 167 | echo "$i: $current_play\n" 168 | done 169 | read selection 170 | current_play=`echo "$play_file" | head -"$selection" | tail -1` 171 | $run_command "$current_play" 172 | if [ $continue_set -gt 0 ] ; then 173 | new_episode=`expr $episode_set + 1` 174 | new_continue=`expr $continue_set - 1` 175 | `playvideo -c $new_continue -s $season_set -e $new_episode "$play_string"` 176 | fi 177 | exit 0 178 | fi 179 | 180 | elif [ -e "$play_file" ] ; then 181 | if [ $list_set -gt 0 ] ; then 182 | echo "$play_file" 183 | else 184 | $run_command "$play_file" 185 | if [ $continue_set -gt 1 ] ; then 186 | new_episode=`expr $episode_set + 1` 187 | new_continue=`expr $continue_set - 1` 188 | `playvideo -c $new_continue -s $season_set -e $new_episode "$play_string"` 189 | fi 190 | fi 191 | exit 0 192 | else 193 | echo "Error, didn't find video" 194 | fi 195 | -------------------------------------------------------------------------------- /Install/InstallAUISuite.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #Script to make install of AUI Suite very easy 4 | function dependencies() { 5 | ARCH=$1 6 | #Ask to install dependencies 7 | install_method=`pgrep apt-get` 8 | if [ -z $install_method ] ; then 9 | echo "Install dependencies? y/n" 10 | echo "These are necessary for any of the options, so you should probably press y unless you absolutely know you have them already" 11 | read option 12 | if [ $option == "y" ] || [ $option == "Y" ] ; then 13 | if [ "$ARCH" == "armv6l" ] ; then 14 | sudo apt-get install locate curl libboost-dev libboost-regex-dev xterm xfonts-base xfonts-utils youtube-dl axel mpg123 libcurl4-openssl-dev flac sox 15 | else 16 | sudo apt-get install locate curl libboost-dev libboost-regex-dev xterm xfonts-base xfonts-utils youtube-dl axel mpg123 libcurl4-openssl-dev flac sox 17 | fi 18 | fi 19 | fi 20 | } 21 | 22 | function playvideo_install() { 23 | #Install playvideo script 24 | echo "Install playvideo? y/n" 25 | echo "This script indexes your movies and tv shows in order to quickly find, randomize, and/or play them. I find it extremely useful" 26 | read option 27 | if [ $option == "y" ] || [ $option == "Y" ] ; then 28 | echo "Installing playvideo" 29 | echo "Enter movie/video root folder location, ex: /media/External/movies" 30 | read media_path 31 | `../PlayVideoScripts/playvideo -set "$media_path"` 32 | sudo cp ../PlayVideoScripts/playvideo /usr/bin/playvideo 33 | sudo cp ../PlayVideoScripts/playvideo.8.gz /usr/share/man/man8/ 34 | echo "Done installing playvideo!" 35 | else 36 | echo "Skipping playvideo install" 37 | fi 38 | } 39 | 40 | function download() { 41 | DIR=$1 42 | USER_HOME="$2" 43 | #Install downloader script 44 | echo "Install downloader? y/n" 45 | echo "This script automates the download of torrents. Ex. 'download wheezy' finds and downloads the newest debian wheezy image" 46 | read option 47 | if [ $option == "y" ] || [ $option == "Y" ] ; then 48 | echo "Installing downloader script" 49 | echo "Enter host: ex, localhost (this is probably what it is)" 50 | read host 51 | echo "Enter Port: default is 9091 I believe" 52 | read port 53 | echo "Enter username, press enter if none" 54 | read user 55 | echo "Enter password, press enter if none" 56 | read passwd 57 | #print commands to $USER_HOME/.down.info 58 | if [ -e "$USER_HOME/.down.info" ] ; then 59 | sudo rm -f "$USER_HOME/.down.info" 60 | fi 61 | echo "$host" | sudo tee -a "$USER_HOME/.down.info" >/dev/null 62 | echo "$port" | sudo tee -a "$USER_HOME/.down.info" >/dev/null 63 | echo "$user" | sudo tee -a "$USER_HOME/.down.info" >/dev/null 64 | echo "$passwd" | sudo tee -a "$USER_HOME/.down.info" >/dev/null 65 | tmp="../DownloadController/" 66 | tmp+="$DIR" 67 | tmp+="download" 68 | sudo cp "$tmp" /usr/bin/download 69 | echo "Done installing download!" 70 | else 71 | echo "Skipping downloader install" 72 | fi 73 | } 74 | 75 | function gvapi() { 76 | DIR=$1 77 | USER_HOME="$2" 78 | #Install gvapi 79 | echo "Install gvapi (googlevoice api)? y/n" 80 | echo "This script installs the google voice api. It is really useful for home automation/robotics enthusiasts." 81 | read option 82 | if [ $option == "y" ] || [ $option == "Y" ] ; then 83 | echo "Installing Text Command Script" 84 | echo "Enter google voice username: " 85 | read user 86 | echo "Enter google voice password: " 87 | read passwd 88 | #print commands to $USER_HOME/.gtext 89 | if [ -e "$USER_HOME/.gv" ] ; then 90 | sudo rm -f "$USER_HOME/.gv" 91 | fi 92 | echo "$user" | sudo tee -a "$USER_HOME/.gv" >/dev/null 93 | echo "$passwd" | sudo tee -a "$USER_HOME/.gv" >/dev/null 94 | tmp="../TextCommand/" 95 | tmp+="$DIR" 96 | tmp+="gvapi" 97 | sudo cp "$tmp" /usr/bin/gvapi 98 | sudo cp ../TextCommand/gvapi.8.gz /usr/share/man/man8/ 99 | echo "Done installing gvapi!" 100 | else 101 | echo "Skipping gvapi install" 102 | fi 103 | } 104 | 105 | function gtextcommand { 106 | DIR=$1 107 | USER_HOME="$2" 108 | #Install gtextcommand script 109 | echo "Install gtextcommand (google voice text command system)? y/n" 110 | echo "This installs gtextcommand. This uses google voice to check for system commands from your number with a passcode." 111 | read option 112 | if [ $option == "y" ] || [ $option == "Y" ] ; then 113 | echo "Installing Text Command Script" 114 | echo "Enter google voice username: " 115 | read user 116 | echo "Enter google voice password: " 117 | read passwd 118 | echo "Enter command keyword, ex: Cmd (this will proceed every vaild command)" 119 | read key 120 | echo "Enter valid number to accept commands from (make sure to put the country code but not the +) ex: 15553334444" 121 | read number 122 | #print commands to $USER_HOME/.gtext 123 | if [ -e "$USER_HOME/.gtext" ] ; then 124 | sudo rm -f "$USER_HOME/.gtext" 125 | fi 126 | echo "$user" | sudo tee -a "$USER_HOME/.gtext" >/dev/null 127 | echo "$passwd" | sudo tee -a "$USER_HOME/.gtext" >/dev/null 128 | echo "$key" | sudo tee -a "$USER_HOME/.gtext" >/dev/null 129 | echo "$number" | sudo tee -a "$USER_HOME/.gtext" >/dev/null 130 | tmp="../TextCommand/" 131 | tmp+="$DIR" 132 | tmp+="gtextcommand" 133 | sudo cp "$tmp" /usr/bin/gtextcommand 134 | #Add to cron.d 135 | echo "Done installing, setting up cron script ..." 136 | if [ -e "/etc/cron.d/gtextcommand" ] ; then 137 | sudo rm -f "/etc/cron.d/gtextcommand" 138 | fi 139 | cronjob="#!/bin/sh 140 | # 141 | # cron script to check google voice. 142 | # 143 | # Written by Steven Hickson for the gtextcommand script. 144 | # 145 | DISPLAY=:0 146 | 147 | * * * * * $USER gtextcommand 148 | 149 | " 150 | echo "$cronjob" | sudo tee -a /etc/cron.d/gtextcommand >/dev/null 151 | sudo sh -c 'chmod +x /etc/cron.d/gtextcommand' 152 | echo "Done installing gtextcommand!" 153 | else 154 | echo "Skipping gtextcommand install" 155 | fi 156 | } 157 | 158 | function youtube() { 159 | DIR=$1 160 | USER_HOME="$2" 161 | echo "Install youtube scripts? y/n" 162 | echo "This installs youtube, youtube-safe, youtube-dl, and other scripts that allow you to download, stream, and browse videos from many sites" 163 | read option 164 | if [ $option == "y" ] || [ $option == "Y" ] ; then 165 | tmp="../Youtube/" 166 | tmp+="$DIR" 167 | tmp+="youtube-search" 168 | sudo cp ../Youtube/youtube /usr/bin/ 169 | sudo cp ../Youtube/youtube-safe /usr/bin/ 170 | sudo cp ../Youtube/youtube-dlfast /usr/bin/ 171 | sudo cp "$tmp" /usr/bin/ 172 | sudo cp ../Youtube/update-youtubedl /etc/cron.daily/ 173 | sudo cp ../Youtube/yt.desktop /usr/share/applications/ 174 | sudo cp ../Youtube/ytb.desktop /usr/share/applications/ 175 | mkdir -p "$USER_HOME/.local/share/midori/scripts" 176 | cp ../Youtube/yt.js "$USER_HOME/.local/share/midori/scripts/" 177 | cp ../Youtube/ytb.js "$USER_HOME/.local/share/midori/scripts/" 178 | #This however, I'm fairly certain I need 179 | sudo update-desktop-database 180 | sudo youtube-dl -U 181 | else 182 | echo "Skipping youtube install" 183 | fi 184 | } 185 | 186 | function voicecommand_install() { 187 | DIR=$1 188 | USER_HOME="$2" 189 | echo "Install voicecommand? y/n" 190 | echo "This is probably the coolest script here and ties many of these together. It is an easily customizable voice control system. It uses speech recognition and text to speech to listen to you, respond to you, and run commands based on what you say." 191 | read option 192 | if [ $option == "y" ] || [ $option == "Y" ] ; then 193 | tmp="../VoiceCommand/" 194 | tmp+="$DIR" 195 | tmp+="voicecommand" 196 | sudo cp "$tmp" /usr/bin/ 197 | sudo cp ../VoiceCommand/google /usr/bin/ 198 | sudo cp ../VoiceCommand/tts /usr/bin/ 199 | sudo cp ../VoiceCommand/speech-recog.sh /usr/bin/ 200 | sudo cp ../VoiceCommand/voicecommand.8.gz /usr/share/man/man8/ 201 | if [[ ! -f "$USER_HOME/.commands.conf" ]] ; then 202 | echo "No commands found, using default" 203 | cp ../VoiceCommand/commands.conf "$USER_HOME/.commands.conf" 204 | else 205 | echo "I found a command file" 206 | fi 207 | echo "Would you like voicecommand to try to set itself up? y/n" 208 | read option 209 | if [ $option == "y" ] || [ $option == "Y" ] ; then 210 | voicecommand -s 211 | else 212 | echo "You can do this manually at any time by running voicecommand -s" 213 | fi 214 | else 215 | echo "Skipping voicecommand install" 216 | fi 217 | } 218 | 219 | echo "Installing AUI Suite by Steven Hickson" 220 | echo "If you have issues, visit stevenhickson.blogspot.com or email help@stevenhickson.com" 221 | 222 | #Get architecture 223 | ARCH=`uname -m` 224 | if [ "$ARCH" == "armv6l" ] ; then 225 | DIR="" 226 | elif [ "$ARCH" == "x86" ] ; then 227 | DIR="x86/" 228 | elif [ "$ARCH" == "x86_64" ] ; then 229 | DIR="x64/" 230 | fi 231 | 232 | if [ "$(id -u)" != "0" ]; then 233 | USER_HOME="$HOME" 234 | else 235 | USER_HOME="/home/${SUDO_USER}" 236 | fi 237 | 238 | ARG="$1" 239 | if [ "$ARG" == "dependencies" ] ; then 240 | dependencies "$ARCH" 241 | elif [ "$ARG" == "playvideo" ] ; then 242 | playvideo_install 243 | elif [ "$ARG" == "download" ] ; then 244 | download "$DIR" "$USER_HOME" 245 | elif [ "$ARG" == "gtextcommand" ] ; then 246 | gtextcommand "$DIR" "$USER_HOME" 247 | elif [ "$ARG" == "gvapi" ] ; then 248 | gvapi "$DIR" "$USER_HOME" 249 | elif [ "$ARG" == "youtube" ] ; then 250 | youtube "$DIR" "$USER_HOME" 251 | elif [ "$ARG" == "voicecommand" ] ; then 252 | voicecommand_install "$DIR" "$USER_HOME" 253 | else 254 | dependencies "$ARCH" 255 | playvideo_install 256 | download "$DIR" "$USER_HOME" 257 | gtextcommand "$DIR" "$USER_HOME" 258 | gvapi "$DIR" "$USER_HOME" 259 | youtube "$DIR" "$USER_HOME" 260 | voicecommand_install "$DIR" "$USER_HOME" 261 | fi 262 | -------------------------------------------------------------------------------- /TextCommand/gvoice.cpp: -------------------------------------------------------------------------------- 1 | // GoogleVoice API. Created by Steven Hickson ported from mastermind202 2 | #define GV_VERSION "v1.0.1" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "gvoice.h" 8 | 9 | using namespace std; 10 | using namespace boost; 11 | 12 | GoogleVoice::GoogleVoice() {hcurl=NULL; loggedin=0; debug=0; version=GV_VERSION;} 13 | GoogleVoice::~GoogleVoice() {if(hcurl) curl_easy_cleanup(hcurl);} 14 | 15 | int GoogleVoice::SendSMS(string number, string msg) 16 | { 17 | if(!hcurl) {cout << "hcurl is NULL. Did you forget to call Init()?\n"; return -1;} 18 | if(Login()) return -1; 19 | 20 | curl_easy_setopt(hcurl, CURLOPT_URL, "https://www.google.com/voice/sms/send/"); 21 | curl_easy_setopt(hcurl, CURLOPT_POST, 1); 22 | 23 | string data = "_rnr_se="+rnr_se; 24 | data += "&phoneNumber=1"+number; 25 | data += "&text="+msg; 26 | 27 | curl_easy_setopt(hcurl, CURLOPT_POSTFIELDS, data.c_str()); // TODO: check this and make sure it doesnt hold on to passed data ptr. 28 | curlbuf.clear(); cr=curl_easy_perform(hcurl); 29 | if(cr!=CURLE_OK) {cout << "curl() error on sending sms: " << errorbuf << endl; return -3;} 30 | 31 | if(debug&2) cout << "\nSendSMS curlbuf: [" << curlbuf << "]\n"; 32 | 33 | regex rexp("\"data\":\\{\"code\":(\\d+)\\}"); cmatch m; 34 | if(regex_search(curlbuf.c_str(), m, rexp)) {string t=m[1]; return atoi(t.c_str());} 35 | else {cout << "Something went wrong. Enable debugging.\n"; return -1;} 36 | 37 | return -1; 38 | } 39 | 40 | int GoogleVoice::MarkAsRead(string msg_id) 41 | { 42 | curl_easy_setopt(hcurl, CURLOPT_URL, "https://www.google.com/voice/inbox/mark/"); 43 | curl_easy_setopt(hcurl, CURLOPT_POST, 1); 44 | 45 | string data = "messages="+msg_id; 46 | data += "&read=1"; 47 | data += "&_rnr_se="+rnr_se; 48 | 49 | curl_easy_setopt(hcurl, CURLOPT_POSTFIELDS, data.c_str()); // TODO: check this and make sure it doesnt hold on to passed data ptr. 50 | curlbuf.clear(); cr=curl_easy_perform(hcurl); 51 | if(cr!=CURLE_OK) {cout << "curl() error on marking sms as read: " << errorbuf << endl; return -3;} 52 | return 0; 53 | } 54 | 55 | int GoogleVoice::GetContactInfo() { 56 | if(!hcurl) {cout << "hcurl is NULL. Did you forget to call Init()?\n"; return -1;} 57 | loggedin = false; //we need to do this because the contact info is in the login page and if they have old cookies. This will never happen 58 | if(Login()) return -1; 59 | 60 | string curlbuf = contact_buf; 61 | 62 | regex rexp("'contacts'"); cmatch m; 63 | if(regex_search(curlbuf.c_str(), m, rexp)) { 64 | //printf("Found contacts\n"); 65 | regex rexp2("\"name\":\"([a-zA-Z0-9 -]+)\",\"photoUrl\":\"\",\"phoneNumber\":\"\\+(\\d+)\""); smatch n; 66 | string::const_iterator begin = curlbuf.begin(), end = curlbuf.end(); 67 | while(regex_search(begin, end, n, rexp2)) { 68 | smatch::value_type r = n[1]; 69 | begin = r.second; 70 | string name = n[1]; 71 | string number = n[2]; 72 | printf("%s==+%s\n",name.c_str(),number.c_str()); 73 | } 74 | } 75 | return 0; 76 | } 77 | 78 | int GoogleVoice::DeleteSMS(string msg_id) 79 | { 80 | curl_easy_setopt(hcurl, CURLOPT_URL, "https://www.google.com/voice/inbox/deleteMessages/"); 81 | curl_easy_setopt(hcurl, CURLOPT_POST, 1); 82 | 83 | string data = "messages="+msg_id; 84 | data += "&trash=1"; 85 | data += "&_rnr_se="+rnr_se; 86 | 87 | curl_easy_setopt(hcurl, CURLOPT_POSTFIELDS, data.c_str()); // TODO: check this and make sure it doesnt hold on to passed data ptr. 88 | curlbuf.clear(); cr=curl_easy_perform(hcurl); 89 | if(cr!=CURLE_OK) {cout << "curl() error on deleting sms: " << errorbuf << endl; return -3;} 90 | return 0; 91 | } 92 | 93 | int GoogleVoice::BlockSMS(string msg_id) 94 | { 95 | curl_easy_setopt(hcurl, CURLOPT_URL, "https://www.google.com/voice/inbox/mark/"); 96 | curl_easy_setopt(hcurl, CURLOPT_POST, 1); 97 | 98 | string data = "messages="+msg_id; 99 | data += "&spam=1"; 100 | data += "&_rnr_se="+rnr_se; 101 | 102 | curl_easy_setopt(hcurl, CURLOPT_POSTFIELDS, data.c_str()); // TODO: check this and make sure it doesnt hold on to passed data ptr. 103 | curlbuf.clear(); cr=curl_easy_perform(hcurl); 104 | if(cr!=CURLE_OK) {cout << "curl() error on marking sms as read: " << errorbuf << endl; return -3;} 105 | return 0; 106 | } 107 | 108 | int GoogleVoice::CallNumber(string to, string from) { 109 | if(!hcurl) {cout << "hcurl is NULL. Did you forget to call Init()?\n"; return -1;} 110 | if(Login()) return -1; 111 | 112 | curl_easy_setopt(hcurl, CURLOPT_URL, "https://www.google.com/voice/call/connect/"); 113 | curl_easy_setopt(hcurl, CURLOPT_POST, 1); 114 | 115 | string data = "forwardingNumber="+from; 116 | data += "&outgoingNumber="+to; 117 | data += "&_rnr_se="+rnr_se; 118 | data += "&phoneType=2&remember=0&subscriberNumber=undefined"; 119 | 120 | curl_easy_setopt(hcurl, CURLOPT_POSTFIELDS, data.c_str()); // TODO: check this and make sure it doesnt hold on to passed data ptr. 121 | curlbuf.clear(); cr=curl_easy_perform(hcurl); 122 | if(cr!=CURLE_OK) {cout << "curl() error on marking sms as read: " << errorbuf << endl; return -3;} 123 | 124 | return 0; 125 | } 126 | 127 | int GoogleVoice::CheckSMS(string &results, string number, string keyword, bool delete_sms) 128 | { 129 | if(!hcurl) {cout << "hcurl is NULL. Did you forget to call Init()?\n"; return -1;} 130 | if(Login()) return -1; 131 | 132 | results = ""; 133 | 134 | curl_easy_setopt(hcurl, CURLOPT_URL, "https://www.google.com/voice/inbox/recent/unread"); 135 | //Doesn't need any post information since it's getting the XML file (focus on unread as it saves a ton of memory/time) 136 | 137 | curlbuf.clear(); cr=curl_easy_perform(hcurl); 138 | if(cr!=CURLE_OK) {cout << "curl() error on getting sms: " << errorbuf << endl; return -3;} 139 | 140 | if(debug&2) cout << "\nSendSMS curlbuf: [" << curlbuf << "]\n"; 141 | string orig = curlbuf; 142 | 143 | regex rexp("\"unread\":(\\d+)"); cmatch m; 144 | if(regex_search(curlbuf.c_str(), m, rexp)) { 145 | string t=m[1]; 146 | int num_unread = atoi(t.c_str()); 147 | //cout << num_unread << "\n" << curlbuf.c_str() << "\n"; 148 | if(num_unread == 0) { 149 | return 0; 150 | } else { 151 | string msg_id; 152 | string reg_check="\"id\":\"([a-z0-9]+)\","; 153 | if(number != "") { 154 | reg_check += "\"phoneNumber\":\"\\+"; 155 | reg_check += number; 156 | reg_check += "\""; 157 | } 158 | regex rexp3(reg_check); cmatch q; 159 | if(regex_search(orig.c_str(), q, rexp3)) { 160 | msg_id=q[1]; 161 | //cout << msg_id.c_str() << "\n"; 162 | } else { 163 | //cout << "Couldn't read msg_id.\n"; 164 | return -1; 165 | } 166 | //printf("First check passed!\n"); 167 | //reg_check = number; 168 | string name = ""; 169 | if(number == "") { 170 | reg_check ="class=\"gc-message-sms-from\">(.+?)"; 171 | regex rexp2(reg_check); cmatch n; 172 | string::const_iterator begin = curlbuf.begin(), end = curlbuf.end(); 173 | smatch p; 174 | while(regex_search(begin, end, p, rexp2)) { 175 | smatch::value_type r = p[1]; 176 | begin = r.second; 177 | string t2 = p[1]; 178 | name = t2; 179 | } 180 | } 181 | reg_check ="class=\"gc-message-sms-text\">"; 182 | if(keyword != "") { 183 | reg_check+=keyword; 184 | reg_check+=" "; 185 | } 186 | reg_check+="(.+?)"; 187 | regex rexp2(reg_check); cmatch n; 188 | //regex rexp2("\"gc-message-sms-text\">([\\/ / /|/.\">"); cmatch n; 189 | string::const_iterator begin = curlbuf.begin(), end = curlbuf.end(); 190 | smatch p; 191 | while(regex_search(begin, end, p, rexp2)) { 192 | smatch::value_type r = p[1]; 193 | begin = r.second; 194 | string t2 = p[1]; 195 | //results += t2; 196 | //results += "\n"; 197 | results = t2; 198 | } 199 | if(name != "") 200 | results = name + results; 201 | if(results != "") { 202 | //printf("Second check passed!\n"); 203 | MarkAsRead(msg_id); 204 | reg_check = "gc-message-sms-text(.+?)phoneNumber"; 205 | regex rexpPhony(reg_check); cmatch f; 206 | if(regex_search(orig.c_str(), f, rexpPhony)) { 207 | //someone is trying to spoof me and this is invalid 208 | SendSMS(number,string("Spoof attack!")); 209 | //BlockSMS(msg_id); 210 | //DeleteSMS(msg_id); 211 | results.clear(); 212 | //By exiting here, they will never be able to spoof the phoneNumber query 213 | return -4; 214 | } else if(delete_sms) 215 | DeleteSMS(msg_id); 216 | //printf("Third check passed!\n"); 217 | } 218 | } 219 | return num_unread; 220 | } else {cout << "Something went wrong. Enable debugging.\n"; return -1;} 221 | 222 | return 0; 223 | 224 | } 225 | 226 | int GoogleVoice::Login(string email, string passwd) 227 | { 228 | if(email.length()<1 || email.length()<1) return -1; 229 | this->email=email; this->passwd=passwd; 230 | return Login(); 231 | } 232 | 233 | int GoogleVoice::Login() 234 | { 235 | if(!hcurl) {cout << "hcurl is NULL. Did you forget to call Init()?\n"; return -1;} 236 | if(loggedin) return 0; 237 | 238 | regex rexp; cmatch m; 239 | string post, galx; 240 | 241 | // Get GLAX token. 242 | curl_easy_setopt(hcurl, CURLOPT_URL, "https://accounts.google.com/ServiceLogin?service=grandcentral"); 243 | curlbuf.clear(); cr=curl_easy_perform(hcurl); 244 | if(cr!=CURLE_OK) {cout << "curl() Error: " << errorbuf << endl; return -1;} 245 | 246 | rexp = "name=\"GALX\"\\s*([\\s\\n\\t]*)value=\"([^\"]+)\""; 247 | if(regex_search(curlbuf.c_str(), m, rexp)) 248 | { 249 | //cout << "Options are: " << m[0] << ", " << m[1] << ", " << m[2] << endl; 250 | galx=m[2]; 251 | if(debug&1) cout << "Got GALX session token: " << galx << endl; 252 | 253 | } else {cout << "Failed to find GALX token.\n"; return -2;} 254 | 255 | // Login and get rnr_se token. 256 | curl_easy_setopt(hcurl, CURLOPT_URL, "https://accounts.google.com/ServiceLoginAuth?service=grandcentral"); 257 | curl_easy_setopt(hcurl, CURLOPT_POST, 1); 258 | post = "Email="+email; 259 | post += "&Passwd="+passwd; 260 | //post += "&PersistantCookie=yes"; 261 | //post += "&bgresponse=js_disabled"; 262 | post += "&continue=https://www.google.com/voice/b/0/"; 263 | post += "&GALX="+galx; 264 | curl_easy_setopt(hcurl, CURLOPT_POSTFIELDS, post.c_str()); // TODO: check this and make sure it doesnt hold on to passed data ptr. 265 | curlbuf.clear(); cr=curl_easy_perform(hcurl); 266 | if(cr!=CURLE_OK) {cout << "curl() Error: " << errorbuf << endl; return -3;} 267 | 268 | if(debug&2) cout << "\nLogin() curlbuf: [" << curlbuf << "]\n"; 269 | 270 | //specifically for contacts 271 | contact_buf = curlbuf; 272 | 273 | rexp = "name=\"_rnr_se\"\\s*type=\"hidden\"([\\s\\n\\t]*)value=\"([^\"]+)\""; 274 | if(regex_search(curlbuf.c_str(), m, rexp)) 275 | { 276 | //cout << "Options are: " << m[0] << ", " << m[1] << ", " << m[2] << endl; 277 | rnr_se=m[2]; loggedin=1; 278 | if(debug&1) cout << "Got rnr_se session token: " << rnr_se << endl; 279 | } 280 | else 281 | { 282 | cout << "Failed to find rnr_se token. (Most likely a bad/mistyped email/passwd)\n"; 283 | loggedin=0; 284 | return -2; 285 | } 286 | FILE *fp; 287 | fp = fopen(DTFILE,"w"); 288 | if(fp == NULL) { 289 | printf("ERROR writing time for cookies\n"); 290 | exit(-1); 291 | } 292 | time_t now; 293 | time(&now); 294 | fprintf(fp,"%s\n%Lu",rnr_se.c_str(),(unsigned long long int)now); 295 | fclose(fp); 296 | return 0; 297 | } 298 | 299 | bool timeisup(FILE* fp, string &rnr) { 300 | if(fp == NULL) 301 | return true; 302 | //lazy method 303 | unsigned long long int orig_time; 304 | char buff[200]; 305 | fscanf(fp,"%s\n%Lu",buff,&orig_time); 306 | fclose(fp); 307 | rnr = string(buff); 308 | time_t now, orig; 309 | orig = (time_t)orig_time; 310 | time(&now); 311 | double seconds = difftime(now,orig); 312 | if(seconds >= 86400) 313 | return true; 314 | return false; 315 | //should maybe use a portable method 316 | } 317 | 318 | int GoogleVoice::Init(void) 319 | { 320 | hcurl=curl_easy_init(); if(!hcurl) return -1; 321 | curl_easy_setopt(hcurl, CURLOPT_ERRORBUFFER, errorbuf); 322 | curl_easy_setopt(hcurl, CURLOPT_WRITEFUNCTION, CurlWriter); 323 | curl_easy_setopt(hcurl, CURLOPT_WRITEDATA, &curlbuf); 324 | curl_easy_setopt(hcurl, CURLOPT_SSL_VERIFYPEER, true); 325 | curl_easy_setopt(hcurl, CURLOPT_SSL_VERIFYHOST, 2); 326 | 327 | curl_easy_setopt(hcurl, CURLOPT_HEADER, 0); 328 | curl_easy_setopt(hcurl, CURLOPT_FOLLOWLOCATION, 1); 329 | curl_easy_setopt(hcurl, CURLOPT_USERAGENT, "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.8) Gecko/20100804 Gentoo Firefox/3.6.8"); 330 | 331 | //check to see what time we last wrote the cookiefile 332 | FILE *fp; 333 | fp = fopen(DTFILE,"r"); 334 | if(timeisup(fp,rnr_se)) { 335 | curl_easy_setopt(hcurl, CURLOPT_COOKIEJAR, "/dev/shm/cookie.txt"); 336 | } else { 337 | //Need to test 24 cookie use here with CURLOPT_COOKIEFILE that way we don't have to keep logging in all the time 338 | curl_easy_setopt(hcurl, CURLOPT_COOKIEFILE, "/dev/shm/cookie.txt"); 339 | loggedin = true; 340 | } 341 | return 0; 342 | } 343 | 344 | int GoogleVoice::CurlWriter(char *data, size_t size, size_t nmemb, string *buffer) 345 | { 346 | if(buffer!=NULL) {buffer->append(data, size*nmemb); return size*nmemb;} 347 | return 0; 348 | } 349 | 350 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | All files included are Copyright (C) 2013 Steven Hickson based off the GPLv3.0 2 | There is a slight caveat, that if you use my software, like it, and meet me, you buy me a drink or something. 3 | 4 | The basic GPL is shown below: 5 | 6 | GNU GENERAL PUBLIC LICENSE 7 | Version 3, 29 June 2007 8 | 9 | Copyright (C) 2007 Free Software Foundation, Inc. 10 | Everyone is permitted to copy and distribute verbatim copies 11 | of this license document, but changing it is not allowed. 12 | 13 | Preamble 14 | 15 | The GNU General Public License is a free, copyleft license for 16 | software and other kinds of works. 17 | 18 | The licenses for most software and other practical works are designed 19 | to take away your freedom to share and change the works. By contrast, 20 | the GNU General Public License is intended to guarantee your freedom to 21 | share and change all versions of a program--to make sure it remains free 22 | software for all its users. We, the Free Software Foundation, use the 23 | GNU General Public License for most of our software; it applies also to 24 | any other work released this way by its authors. You can apply it to 25 | your programs, too. 26 | 27 | When we speak of free software, we are referring to freedom, not 28 | price. Our General Public Licenses are designed to make sure that you 29 | have the freedom to distribute copies of free software (and charge for 30 | them if you wish), that you receive source code or can get it if you 31 | want it, that you can change the software or use pieces of it in new 32 | free programs, and that you know you can do these things. 33 | 34 | To protect your rights, we need to prevent others from denying you 35 | these rights or asking you to surrender the rights. Therefore, you have 36 | certain responsibilities if you distribute copies of the software, or if 37 | you modify it: responsibilities to respect the freedom of others. 38 | 39 | For example, if you distribute copies of such a program, whether 40 | gratis or for a fee, you must pass on to the recipients the same 41 | freedoms that you received. You must make sure that they, too, receive 42 | or can get the source code. And you must show them these terms so they 43 | know their rights. 44 | 45 | Developers that use the GNU GPL protect your rights with two steps: 46 | (1) assert copyright on the software, and (2) offer you this License 47 | giving you legal permission to copy, distribute and/or modify it. 48 | 49 | For the developers' and authors' protection, the GPL clearly explains 50 | that there is no warranty for this free software. For both users' and 51 | authors' sake, the GPL requires that modified versions be marked as 52 | changed, so that their problems will not be attributed erroneously to 53 | authors of previous versions. 54 | 55 | Some devices are designed to deny users access to install or run 56 | modified versions of the software inside them, although the manufacturer 57 | can do so. This is fundamentally incompatible with the aim of 58 | protecting users' freedom to change the software. The systematic 59 | pattern of such abuse occurs in the area of products for individuals to 60 | use, which is precisely where it is most unacceptable. Therefore, we 61 | have designed this version of the GPL to prohibit the practice for those 62 | products. If such problems arise substantially in other domains, we 63 | stand ready to extend this provision to those domains in future versions 64 | of the GPL, as needed to protect the freedom of users. 65 | 66 | Finally, every program is threatened constantly by software patents. 67 | States should not allow patents to restrict development and use of 68 | software on general-purpose computers, but in those that do, we wish to 69 | avoid the special danger that patents applied to a free program could 70 | make it effectively proprietary. To prevent this, the GPL assures that 71 | patents cannot be used to render the program non-free. 72 | 73 | The precise terms and conditions for copying, distribution and 74 | modification follow. 75 | 76 | TERMS AND CONDITIONS 77 | 78 | 0. Definitions. 79 | 80 | "This License" refers to version 3 of the GNU General Public License. 81 | 82 | "Copyright" also means copyright-like laws that apply to other kinds of 83 | works, such as semiconductor masks. 84 | 85 | "The Program" refers to any copyrightable work licensed under this 86 | License. Each licensee is addressed as "you". "Licensees" and 87 | "recipients" may be individuals or organizations. 88 | 89 | To "modify" a work means to copy from or adapt all or part of the work 90 | in a fashion requiring copyright permission, other than the making of an 91 | exact copy. The resulting work is called a "modified version" of the 92 | earlier work or a work "based on" the earlier work. 93 | 94 | A "covered work" means either the unmodified Program or a work based 95 | on the Program. 96 | 97 | To "propagate" a work means to do anything with it that, without 98 | permission, would make you directly or secondarily liable for 99 | infringement under applicable copyright law, except executing it on a 100 | computer or modifying a private copy. Propagation includes copying, 101 | distribution (with or without modification), making available to the 102 | public, and in some countries other activities as well. 103 | 104 | To "convey" a work means any kind of propagation that enables other 105 | parties to make or receive copies. Mere interaction with a user through 106 | a computer network, with no transfer of a copy, is not conveying. 107 | 108 | An interactive user interface displays "Appropriate Legal Notices" 109 | to the extent that it includes a convenient and prominently visible 110 | feature that (1) displays an appropriate copyright notice, and (2) 111 | tells the user that there is no warranty for the work (except to the 112 | extent that warranties are provided), that licensees may convey the 113 | work under this License, and how to view a copy of this License. If 114 | the interface presents a list of user commands or options, such as a 115 | menu, a prominent item in the list meets this criterion. 116 | 117 | 1. Source Code. 118 | 119 | The "source code" for a work means the preferred form of the work 120 | for making modifications to it. "Object code" means any non-source 121 | form of a work. 122 | 123 | A "Standard Interface" means an interface that either is an official 124 | standard defined by a recognized standards body, or, in the case of 125 | interfaces specified for a particular programming language, one that 126 | is widely used among developers working in that language. 127 | 128 | The "System Libraries" of an executable work include anything, other 129 | than the work as a whole, that (a) is included in the normal form of 130 | packaging a Major Component, but which is not part of that Major 131 | Component, and (b) serves only to enable use of the work with that 132 | Major Component, or to implement a Standard Interface for which an 133 | implementation is available to the public in source code form. A 134 | "Major Component", in this context, means a major essential component 135 | (kernel, window system, and so on) of the specific operating system 136 | (if any) on which the executable work runs, or a compiler used to 137 | produce the work, or an object code interpreter used to run it. 138 | 139 | The "Corresponding Source" for a work in object code form means all 140 | the source code needed to generate, install, and (for an executable 141 | work) run the object code and to modify the work, including scripts to 142 | control those activities. However, it does not include the work's 143 | System Libraries, or general-purpose tools or generally available free 144 | programs which are used unmodified in performing those activities but 145 | which are not part of the work. For example, Corresponding Source 146 | includes interface definition files associated with source files for 147 | the work, and the source code for shared libraries and dynamically 148 | linked subprograms that the work is specifically designed to require, 149 | such as by intimate data communication or control flow between those 150 | subprograms and other parts of the work. 151 | 152 | The Corresponding Source need not include anything that users 153 | can regenerate automatically from other parts of the Corresponding 154 | Source. 155 | 156 | The Corresponding Source for a work in source code form is that 157 | same work. 158 | 159 | 2. Basic Permissions. 160 | 161 | All rights granted under this License are granted for the term of 162 | copyright on the Program, and are irrevocable provided the stated 163 | conditions are met. This License explicitly affirms your unlimited 164 | permission to run the unmodified Program. The output from running a 165 | covered work is covered by this License only if the output, given its 166 | content, constitutes a covered work. This License acknowledges your 167 | rights of fair use or other equivalent, as provided by copyright law. 168 | 169 | You may make, run and propagate covered works that you do not 170 | convey, without conditions so long as your license otherwise remains 171 | in force. You may convey covered works to others for the sole purpose 172 | of having them make modifications exclusively for you, or provide you 173 | with facilities for running those works, provided that you comply with 174 | the terms of this License in conveying all material for which you do 175 | not control copyright. Those thus making or running the covered works 176 | for you must do so exclusively on your behalf, under your direction 177 | and control, on terms that prohibit them from making any copies of 178 | your copyrighted material outside their relationship with you. 179 | 180 | Conveying under any other circumstances is permitted solely under 181 | the conditions stated below. Sublicensing is not allowed; section 10 182 | makes it unnecessary. 183 | 184 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 185 | 186 | No covered work shall be deemed part of an effective technological 187 | measure under any applicable law fulfilling obligations under article 188 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 189 | similar laws prohibiting or restricting circumvention of such 190 | measures. 191 | 192 | When you convey a covered work, you waive any legal power to forbid 193 | circumvention of technological measures to the extent such circumvention 194 | is effected by exercising rights under this License with respect to 195 | the covered work, and you disclaim any intention to limit operation or 196 | modification of the work as a means of enforcing, against the work's 197 | users, your or third parties' legal rights to forbid circumvention of 198 | technological measures. 199 | 200 | 4. Conveying Verbatim Copies. 201 | 202 | You may convey verbatim copies of the Program's source code as you 203 | receive it, in any medium, provided that you conspicuously and 204 | appropriately publish on each copy an appropriate copyright notice; 205 | keep intact all notices stating that this License and any 206 | non-permissive terms added in accord with section 7 apply to the code; 207 | keep intact all notices of the absence of any warranty; and give all 208 | recipients a copy of this License along with the Program. 209 | 210 | You may charge any price or no price for each copy that you convey, 211 | and you may offer support or warranty protection for a fee. 212 | 213 | 5. Conveying Modified Source Versions. 214 | 215 | You may convey a work based on the Program, or the modifications to 216 | produce it from the Program, in the form of source code under the 217 | terms of section 4, provided that you also meet all of these conditions: 218 | 219 | a) The work must carry prominent notices stating that you modified 220 | it, and giving a relevant date. 221 | 222 | b) The work must carry prominent notices stating that it is 223 | released under this License and any conditions added under section 224 | 7. This requirement modifies the requirement in section 4 to 225 | "keep intact all notices". 226 | 227 | c) You must license the entire work, as a whole, under this 228 | License to anyone who comes into possession of a copy. This 229 | License will therefore apply, along with any applicable section 7 230 | additional terms, to the whole of the work, and all its parts, 231 | regardless of how they are packaged. This License gives no 232 | permission to license the work in any other way, but it does not 233 | invalidate such permission if you have separately received it. 234 | 235 | d) If the work has interactive user interfaces, each must display 236 | Appropriate Legal Notices; however, if the Program has interactive 237 | interfaces that do not display Appropriate Legal Notices, your 238 | work need not make them do so. 239 | 240 | A compilation of a covered work with other separate and independent 241 | works, which are not by their nature extensions of the covered work, 242 | and which are not combined with it such as to form a larger program, 243 | in or on a volume of a storage or distribution medium, is called an 244 | "aggregate" if the compilation and its resulting copyright are not 245 | used to limit the access or legal rights of the compilation's users 246 | beyond what the individual works permit. Inclusion of a covered work 247 | in an aggregate does not cause this License to apply to the other 248 | parts of the aggregate. 249 | 250 | 6. Conveying Non-Source Forms. 251 | 252 | You may convey a covered work in object code form under the terms 253 | of sections 4 and 5, provided that you also convey the 254 | machine-readable Corresponding Source under the terms of this License, 255 | in one of these ways: 256 | 257 | a) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by the 259 | Corresponding Source fixed on a durable physical medium 260 | customarily used for software interchange. 261 | 262 | b) Convey the object code in, or embodied in, a physical product 263 | (including a physical distribution medium), accompanied by a 264 | written offer, valid for at least three years and valid for as 265 | long as you offer spare parts or customer support for that product 266 | model, to give anyone who possesses the object code either (1) a 267 | copy of the Corresponding Source for all the software in the 268 | product that is covered by this License, on a durable physical 269 | medium customarily used for software interchange, for a price no 270 | more than your reasonable cost of physically performing this 271 | conveying of source, or (2) access to copy the 272 | Corresponding Source from a network server at no charge. 273 | 274 | c) Convey individual copies of the object code with a copy of the 275 | written offer to provide the Corresponding Source. This 276 | alternative is allowed only occasionally and noncommercially, and 277 | only if you received the object code with such an offer, in accord 278 | with subsection 6b. 279 | 280 | d) Convey the object code by offering access from a designated 281 | place (gratis or for a charge), and offer equivalent access to the 282 | Corresponding Source in the same way through the same place at no 283 | further charge. You need not require recipients to copy the 284 | Corresponding Source along with the object code. If the place to 285 | copy the object code is a network server, the Corresponding Source 286 | may be on a different server (operated by you or a third party) 287 | that supports equivalent copying facilities, provided you maintain 288 | clear directions next to the object code saying where to find the 289 | Corresponding Source. Regardless of what server hosts the 290 | Corresponding Source, you remain obligated to ensure that it is 291 | available for as long as needed to satisfy these requirements. 292 | 293 | e) Convey the object code using peer-to-peer transmission, provided 294 | you inform other peers where the object code and Corresponding 295 | Source of the work are being offered to the general public at no 296 | charge under subsection 6d. 297 | 298 | A separable portion of the object code, whose source code is excluded 299 | from the Corresponding Source as a System Library, need not be 300 | included in conveying the object code work. 301 | 302 | A "User Product" is either (1) a "consumer product", which means any 303 | tangible personal property which is normally used for personal, family, 304 | or household purposes, or (2) anything designed or sold for incorporation 305 | into a dwelling. In determining whether a product is a consumer product, 306 | doubtful cases shall be resolved in favor of coverage. For a particular 307 | product received by a particular user, "normally used" refers to a 308 | typical or common use of that class of product, regardless of the status 309 | of the particular user or of the way in which the particular user 310 | actually uses, or expects or is expected to use, the product. A product 311 | is a consumer product regardless of whether the product has substantial 312 | commercial, industrial or non-consumer uses, unless such uses represent 313 | the only significant mode of use of the product. 314 | 315 | "Installation Information" for a User Product means any methods, 316 | procedures, authorization keys, or other information required to install 317 | and execute modified versions of a covered work in that User Product from 318 | a modified version of its Corresponding Source. The information must 319 | suffice to ensure that the continued functioning of the modified object 320 | code is in no case prevented or interfered with solely because 321 | modification has been made. 322 | 323 | If you convey an object code work under this section in, or with, or 324 | specifically for use in, a User Product, and the conveying occurs as 325 | part of a transaction in which the right of possession and use of the 326 | User Product is transferred to the recipient in perpetuity or for a 327 | fixed term (regardless of how the transaction is characterized), the 328 | Corresponding Source conveyed under this section must be accompanied 329 | by the Installation Information. But this requirement does not apply 330 | if neither you nor any third party retains the ability to install 331 | modified object code on the User Product (for example, the work has 332 | been installed in ROM). 333 | 334 | The requirement to provide Installation Information does not include a 335 | requirement to continue to provide support service, warranty, or updates 336 | for a work that has been modified or installed by the recipient, or for 337 | the User Product in which it has been modified or installed. Access to a 338 | network may be denied when the modification itself materially and 339 | adversely affects the operation of the network or violates the rules and 340 | protocols for communication across the network. 341 | 342 | Corresponding Source conveyed, and Installation Information provided, 343 | in accord with this section must be in a format that is publicly 344 | documented (and with an implementation available to the public in 345 | source code form), and must require no special password or key for 346 | unpacking, reading or copying. 347 | 348 | 7. Additional Terms. 349 | 350 | "Additional permissions" are terms that supplement the terms of this 351 | License by making exceptions from one or more of its conditions. 352 | Additional permissions that are applicable to the entire Program shall 353 | be treated as though they were included in this License, to the extent 354 | that they are valid under applicable law. If additional permissions 355 | apply only to part of the Program, that part may be used separately 356 | under those permissions, but the entire Program remains governed by 357 | this License without regard to the additional permissions. 358 | 359 | When you convey a copy of a covered work, you may at your option 360 | remove any additional permissions from that copy, or from any part of 361 | it. (Additional permissions may be written to require their own 362 | removal in certain cases when you modify the work.) You may place 363 | additional permissions on material, added by you to a covered work, 364 | for which you have or can give appropriate copyright permission. 365 | 366 | Notwithstanding any other provision of this License, for material you 367 | add to a covered work, you may (if authorized by the copyright holders of 368 | that material) supplement the terms of this License with terms: 369 | 370 | a) Disclaiming warranty or limiting liability differently from the 371 | terms of sections 15 and 16 of this License; or 372 | 373 | b) Requiring preservation of specified reasonable legal notices or 374 | author attributions in that material or in the Appropriate Legal 375 | Notices displayed by works containing it; or 376 | 377 | c) Prohibiting misrepresentation of the origin of that material, or 378 | requiring that modified versions of such material be marked in 379 | reasonable ways as different from the original version; or 380 | 381 | d) Limiting the use for publicity purposes of names of licensors or 382 | authors of the material; or 383 | 384 | e) Declining to grant rights under trademark law for use of some 385 | trade names, trademarks, or service marks; or 386 | 387 | f) Requiring indemnification of licensors and authors of that 388 | material by anyone who conveys the material (or modified versions of 389 | it) with contractual assumptions of liability to the recipient, for 390 | any liability that these contractual assumptions directly impose on 391 | those licensors and authors. 392 | 393 | All other non-permissive additional terms are considered "further 394 | restrictions" within the meaning of section 10. If the Program as you 395 | received it, or any part of it, contains a notice stating that it is 396 | governed by this License along with a term that is a further 397 | restriction, you may remove that term. If a license document contains 398 | a further restriction but permits relicensing or conveying under this 399 | License, you may add to a covered work material governed by the terms 400 | of that license document, provided that the further restriction does 401 | not survive such relicensing or conveying. 402 | 403 | If you add terms to a covered work in accord with this section, you 404 | must place, in the relevant source files, a statement of the 405 | additional terms that apply to those files, or a notice indicating 406 | where to find the applicable terms. 407 | 408 | Additional terms, permissive or non-permissive, may be stated in the 409 | form of a separately written license, or stated as exceptions; 410 | the above requirements apply either way. 411 | 412 | 8. Termination. 413 | 414 | You may not propagate or modify a covered work except as expressly 415 | provided under this License. Any attempt otherwise to propagate or 416 | modify it is void, and will automatically terminate your rights under 417 | this License (including any patent licenses granted under the third 418 | paragraph of section 11). 419 | 420 | However, if you cease all violation of this License, then your 421 | license from a particular copyright holder is reinstated (a) 422 | provisionally, unless and until the copyright holder explicitly and 423 | finally terminates your license, and (b) permanently, if the copyright 424 | holder fails to notify you of the violation by some reasonable means 425 | prior to 60 days after the cessation. 426 | 427 | Moreover, your license from a particular copyright holder is 428 | reinstated permanently if the copyright holder notifies you of the 429 | violation by some reasonable means, this is the first time you have 430 | received notice of violation of this License (for any work) from that 431 | copyright holder, and you cure the violation prior to 30 days after 432 | your receipt of the notice. 433 | 434 | Termination of your rights under this section does not terminate the 435 | licenses of parties who have received copies or rights from you under 436 | this License. If your rights have been terminated and not permanently 437 | reinstated, you do not qualify to receive new licenses for the same 438 | material under section 10. 439 | 440 | 9. Acceptance Not Required for Having Copies. 441 | 442 | You are not required to accept this License in order to receive or 443 | run a copy of the Program. Ancillary propagation of a covered work 444 | occurring solely as a consequence of using peer-to-peer transmission 445 | to receive a copy likewise does not require acceptance. However, 446 | nothing other than this License grants you permission to propagate or 447 | modify any covered work. These actions infringe copyright if you do 448 | not accept this License. Therefore, by modifying or propagating a 449 | covered work, you indicate your acceptance of this License to do so. 450 | 451 | 10. Automatic Licensing of Downstream Recipients. 452 | 453 | Each time you convey a covered work, the recipient automatically 454 | receives a license from the original licensors, to run, modify and 455 | propagate that work, subject to this License. You are not responsible 456 | for enforcing compliance by third parties with this License. 457 | 458 | An "entity transaction" is a transaction transferring control of an 459 | organization, or substantially all assets of one, or subdividing an 460 | organization, or merging organizations. If propagation of a covered 461 | work results from an entity transaction, each party to that 462 | transaction who receives a copy of the work also receives whatever 463 | licenses to the work the party's predecessor in interest had or could 464 | give under the previous paragraph, plus a right to possession of the 465 | Corresponding Source of the work from the predecessor in interest, if 466 | the predecessor has it or can get it with reasonable efforts. 467 | 468 | You may not impose any further restrictions on the exercise of the 469 | rights granted or affirmed under this License. For example, you may 470 | not impose a license fee, royalty, or other charge for exercise of 471 | rights granted under this License, and you may not initiate litigation 472 | (including a cross-claim or counterclaim in a lawsuit) alleging that 473 | any patent claim is infringed by making, using, selling, offering for 474 | sale, or importing the Program or any portion of it. 475 | 476 | 11. Patents. 477 | 478 | A "contributor" is a copyright holder who authorizes use under this 479 | License of the Program or a work on which the Program is based. The 480 | work thus licensed is called the contributor's "contributor version". 481 | 482 | A contributor's "essential patent claims" are all patent claims 483 | owned or controlled by the contributor, whether already acquired or 484 | hereafter acquired, that would be infringed by some manner, permitted 485 | by this License, of making, using, or selling its contributor version, 486 | but do not include claims that would be infringed only as a 487 | consequence of further modification of the contributor version. For 488 | purposes of this definition, "control" includes the right to grant 489 | patent sublicenses in a manner consistent with the requirements of 490 | this License. 491 | 492 | Each contributor grants you a non-exclusive, worldwide, royalty-free 493 | patent license under the contributor's essential patent claims, to 494 | make, use, sell, offer for sale, import and otherwise run, modify and 495 | propagate the contents of its contributor version. 496 | 497 | In the following three paragraphs, a "patent license" is any express 498 | agreement or commitment, however denominated, not to enforce a patent 499 | (such as an express permission to practice a patent or covenant not to 500 | sue for patent infringement). To "grant" such a patent license to a 501 | party means to make such an agreement or commitment not to enforce a 502 | patent against the party. 503 | 504 | If you convey a covered work, knowingly relying on a patent license, 505 | and the Corresponding Source of the work is not available for anyone 506 | to copy, free of charge and under the terms of this License, through a 507 | publicly available network server or other readily accessible means, 508 | then you must either (1) cause the Corresponding Source to be so 509 | available, or (2) arrange to deprive yourself of the benefit of the 510 | patent license for this particular work, or (3) arrange, in a manner 511 | consistent with the requirements of this License, to extend the patent 512 | license to downstream recipients. "Knowingly relying" means you have 513 | actual knowledge that, but for the patent license, your conveying the 514 | covered work in a country, or your recipient's use of the covered work 515 | in a country, would infringe one or more identifiable patents in that 516 | country that you have reason to believe are valid. 517 | 518 | If, pursuant to or in connection with a single transaction or 519 | arrangement, you convey, or propagate by procuring conveyance of, a 520 | covered work, and grant a patent license to some of the parties 521 | receiving the covered work authorizing them to use, propagate, modify 522 | or convey a specific copy of the covered work, then the patent license 523 | you grant is automatically extended to all recipients of the covered 524 | work and works based on it. 525 | 526 | A patent license is "discriminatory" if it does not include within 527 | the scope of its coverage, prohibits the exercise of, or is 528 | conditioned on the non-exercise of one or more of the rights that are 529 | specifically granted under this License. You may not convey a covered 530 | work if you are a party to an arrangement with a third party that is 531 | in the business of distributing software, under which you make payment 532 | to the third party based on the extent of your activity of conveying 533 | the work, and under which the third party grants, to any of the 534 | parties who would receive the covered work from you, a discriminatory 535 | patent license (a) in connection with copies of the covered work 536 | conveyed by you (or copies made from those copies), or (b) primarily 537 | for and in connection with specific products or compilations that 538 | contain the covered work, unless you entered into that arrangement, 539 | or that patent license was granted, prior to 28 March 2007. 540 | 541 | Nothing in this License shall be construed as excluding or limiting 542 | any implied license or other defenses to infringement that may 543 | otherwise be available to you under applicable patent law. 544 | 545 | 12. No Surrender of Others' Freedom. 546 | 547 | If conditions are imposed on you (whether by court order, agreement or 548 | otherwise) that contradict the conditions of this License, they do not 549 | excuse you from the conditions of this License. If you cannot convey a 550 | covered work so as to satisfy simultaneously your obligations under this 551 | License and any other pertinent obligations, then as a consequence you may 552 | not convey it at all. For example, if you agree to terms that obligate you 553 | to collect a royalty for further conveying from those to whom you convey 554 | the Program, the only way you could satisfy both those terms and this 555 | License would be to refrain entirely from conveying the Program. 556 | 557 | 13. Use with the GNU Affero General Public License. 558 | 559 | Notwithstanding any other provision of this License, you have 560 | permission to link or combine any covered work with a work licensed 561 | under version 3 of the GNU Affero General Public License into a single 562 | combined work, and to convey the resulting work. The terms of this 563 | License will continue to apply to the part which is the covered work, 564 | but the special requirements of the GNU Affero General Public License, 565 | section 13, concerning interaction through a network will apply to the 566 | combination as such. 567 | 568 | 14. Revised Versions of this License. 569 | 570 | The Free Software Foundation may publish revised and/or new versions of 571 | the GNU General Public License from time to time. Such new versions will 572 | be similar in spirit to the present version, but may differ in detail to 573 | address new problems or concerns. 574 | 575 | Each version is given a distinguishing version number. If the 576 | Program specifies that a certain numbered version of the GNU General 577 | Public License "or any later version" applies to it, you have the 578 | option of following the terms and conditions either of that numbered 579 | version or of any later version published by the Free Software 580 | Foundation. If the Program does not specify a version number of the 581 | GNU General Public License, you may choose any version ever published 582 | by the Free Software Foundation. 583 | 584 | If the Program specifies that a proxy can decide which future 585 | versions of the GNU General Public License can be used, that proxy's 586 | public statement of acceptance of a version permanently authorizes you 587 | to choose that version for the Program. 588 | 589 | Later license versions may give you additional or different 590 | permissions. However, no additional obligations are imposed on any 591 | author or copyright holder as a result of your choosing to follow a 592 | later version. 593 | 594 | 15. Disclaimer of Warranty. 595 | 596 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 597 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 598 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 599 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 600 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 601 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 602 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 603 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 604 | 605 | 16. Limitation of Liability. 606 | 607 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 608 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 609 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 610 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 611 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 612 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 613 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 614 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 615 | SUCH DAMAGES. 616 | 617 | 17. Interpretation of Sections 15 and 16. 618 | 619 | If the disclaimer of warranty and limitation of liability provided 620 | above cannot be given local legal effect according to their terms, 621 | reviewing courts shall apply local law that most closely approximates 622 | an absolute waiver of all civil liability in connection with the 623 | Program, unless a warranty or assumption of liability accompanies a 624 | copy of the Program in return for a fee. 625 | 626 | END OF TERMS AND CONDITIONS 627 | 628 | How to Apply These Terms to Your New Programs 629 | 630 | If you develop a new program, and you want it to be of the greatest 631 | possible use to the public, the best way to achieve this is to make it 632 | free software which everyone can redistribute and change under these terms. 633 | 634 | To do so, attach the following notices to the program. It is safest 635 | to attach them to the start of each source file to most effectively 636 | state the exclusion of warranty; and each file should have at least 637 | the "copyright" line and a pointer to where the full notice is found. 638 | 639 | 640 | Copyright (C) 641 | 642 | This program is free software: you can redistribute it and/or modify 643 | it under the terms of the GNU General Public License as published by 644 | the Free Software Foundation, either version 3 of the License, or 645 | (at your option) any later version. 646 | 647 | This program is distributed in the hope that it will be useful, 648 | but WITHOUT ANY WARRANTY; without even the implied warranty of 649 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 650 | GNU General Public License for more details. 651 | 652 | You should have received a copy of the GNU General Public License 653 | along with this program. If not, see . 654 | 655 | Also add information on how to contact you by electronic and paper mail. 656 | 657 | If the program does terminal interaction, make it output a short 658 | notice like this when it starts in an interactive mode: 659 | 660 | Copyright (C) 661 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 662 | This is free software, and you are welcome to redistribute it 663 | under certain conditions; type `show c' for details. 664 | 665 | The hypothetical commands `show w' and `show c' should show the appropriate 666 | parts of the General Public License. Of course, your program's commands 667 | might be different; for a GUI interface, you would use an "about box". 668 | 669 | You should also get your employer (if you work as a programmer) or school, 670 | if any, to sign a "copyright disclaimer" for the program, if necessary. 671 | For more information on this, and how to apply and follow the GNU GPL, see 672 | . 673 | 674 | The GNU General Public License does not permit incorporating your program 675 | into proprietary programs. If your program is a subroutine library, you 676 | may consider it more useful to permit linking proprietary applications with 677 | the library. If this is what you want to do, use the GNU Lesser General 678 | Public License instead of this License. But first, please read 679 | . 680 | -------------------------------------------------------------------------------- /VoiceCommand/voicecommand.cpp: -------------------------------------------------------------------------------- 1 | #include "voicecommand.h" 2 | 3 | using namespace std; 4 | using namespace boost; 5 | 6 | void changemode(int); 7 | int kbhit(void); 8 | 9 | static const char *optString = "I:l:d:D:psb::c::v::ei::q::t:k:r:f:h?"; 10 | 11 | inline void ProcessVoice(FILE *cmd, VoiceCommand &vc, char *message) { 12 | printf("Found audio\n"); 13 | vc.Speak(vc.response); 14 | string command = "speech-recog.sh"; 15 | if(vc.differentHW) { 16 | command += " -D "; 17 | command += vc.recordHW; 18 | } 19 | command += " -d "; 20 | command += vc.duration; 21 | command += " -l "; 22 | command += vc.lang; 23 | cmd = popen(command.c_str(),"r"); 24 | fscanf(cmd,"\"%[^\"\n]\"",message); 25 | vc.ProcessMessage(message); 26 | fclose(cmd); 27 | } 28 | 29 | inline float GetVolume(string recordHW, string com_duration, bool nullout) { 30 | FILE *cmd; 31 | float vol = 0.0f; 32 | string run = "arecord -D "; 33 | run += recordHW; 34 | run += " -t wav -d "; 35 | run += com_duration; 36 | run += " -r 16000 /dev/shm/noise.wav"; 37 | if(nullout) 38 | run += " 1>>/dev/shm/voice.log 2>>/dev/shm/voice.log"; 39 | system(run.c_str()); 40 | cmd = popen("sox /dev/shm/noise.wav -n stats -s 16 2>&1 | awk '/^Max\\ level/ {print $3}'","r"); 41 | fscanf(cmd,"%f",&vol); 42 | fclose(cmd); 43 | return vol; 44 | } 45 | 46 | int main(int argc, char* argv[]) { 47 | VoiceCommand vc; 48 | //this is a really crude and terrible hack. 49 | //It makes it so that the config file doesn't overwrite the command line options 50 | //And it allows the config file to be set to something random 51 | system("echo \"\" > /dev/shm/voice.log"); //lazily clear out the log file 52 | vc.CheckConfigParam(argc,argv); 53 | 54 | FILE *cmd = NULL; 55 | char message[200]; 56 | message[0] = '\0'; 57 | 58 | vc.GetConfig(); 59 | //command line options after the config options 60 | vc.CheckCmdLineParam(argc,argv); 61 | //vc.CheckConfig(); 62 | if(!vc.pid_file.empty()) { 63 | FILE *out; 64 | out = fopen(vc.pid_file.c_str(),"w"); 65 | if(out == NULL) 66 | printf("Can not write to pid file: %s\n",vc.pid_file.c_str()); 67 | else { 68 | fprintf(out,"%d",getpid()); 69 | fclose(out); 70 | printf("Wrote pid file\n"); 71 | } 72 | } 73 | if(vc.quiet) 74 | fprintf(stderr,"running in quiet mode\n"); 75 | if(vc.ignoreOthers) 76 | fprintf(stderr,"Not querying for answers\n"); 77 | if(vc.edit) { 78 | vc.EditConfig(); 79 | } else if(vc.continuous && vc.forced_input.empty()) { 80 | fprintf(stderr,"running in continuous mode\n"); 81 | if(vc.verify) 82 | fprintf(stderr,"verifying command as well\n"); 83 | fprintf(stderr,"keyword duration is %s and duration is %s\n",vc.command_duration.c_str(),vc.duration.c_str()); 84 | float volume = 0.0f; 85 | changemode(1); 86 | string cont_com = "curl -X POST --data-binary @/dev/shm/noise.flac --user-agent 'Mozilla/5.0' --header 'Content-Type: audio/x-flac; rate=16000;' 'https://www.google.com/speech-api/v2/recognize?output=json&lang=" + vc.lang + "&key=AIzaSyBOti4mM-6x9WDnZIjIeyEU21OpBXqWBgw&client=Mozilla/5.0' | sed -e 's/[{}]/''/g' | awk -F\":\" '{print $4}' | awk -F\",\" '{print $1}' | tr -d '\\n'"; 87 | 88 | while(vc.continuous) { 89 | volume = GetVolume(vc.recordHW, vc.command_duration, true); 90 | if(volume > vc.thresh) { 91 | //printf("Found volume %f above thresh %f\n",volume,vc.thresh); 92 | if(vc.verify) { 93 | system("flac /dev/shm/noise.wav -f --best --sample-rate 16000 -o /dev/shm/noise.flac 1>>/dev/shm/voice.log 2>>/dev/shm/voice.log"); 94 | cmd = popen(cont_com.c_str(),"r"); 95 | if(cmd == NULL) 96 | printf("ERROR\n"); 97 | fscanf(cmd,"\"%[^\"\n]\"",message); 98 | fclose(cmd); 99 | system("rm -fr /dev/shm/noise.*"); 100 | //printf("message: %s, keyword: %s\n", message, vc.keyword.c_str()); 101 | if(iequals(message,vc.keyword.c_str())) { 102 | message[0] = '\0'; //this will clear the first bit 103 | ProcessVoice(cmd,vc,message); 104 | } 105 | } else { 106 | ProcessVoice(cmd,vc,message); 107 | } 108 | message[0] = '\0'; //this will clear the first bit 109 | } 110 | if(kbhit()) { 111 | if(getchar() == 27) { 112 | printf("Escaping\n"); 113 | vc.continuous = false; 114 | changemode(0); 115 | } else if(getchar() == 'v') { 116 | if(vc.verify) { 117 | printf("Turning verify off\n"); 118 | vc.verify = false; 119 | } else { 120 | printf("Turning verify on\n"); 121 | vc.verify = true; 122 | } 123 | } 124 | } 125 | } 126 | } else { 127 | if(vc.forced_input.empty()) { 128 | string command = "speech-recog.sh"; 129 | if(vc.differentHW) { 130 | command += " -D "; 131 | command += vc.recordHW; 132 | } 133 | command += " -d "; 134 | command += vc.duration; 135 | command += " -l "; 136 | command += vc.lang; 137 | cmd = popen(command.c_str(),"r"); 138 | fscanf(cmd,"\"%[^\"\n]\"",message); 139 | vc.ProcessMessage(message); 140 | fclose(cmd); 141 | } else { 142 | vc.ProcessMessage(vc.forced_input.c_str()); 143 | } 144 | } 145 | 146 | return 0; 147 | } 148 | 149 | inline void VoiceCommand::CheckConfigParam(int argc, char* argv[]) { 150 | //check to see if they set a different config file 151 | int opt=0; 152 | opt = getopt( argc, argv, optString ); 153 | while( opt != -1 ) { 154 | switch( opt ) { 155 | case 'f': 156 | config_file = string(optarg); 157 | optind=1; 158 | return; 159 | default: 160 | break; 161 | } 162 | opt = getopt( argc, argv, optString ); 163 | } 164 | optind=1; 165 | } 166 | 167 | inline void VoiceCommand::CheckCmdLineParam(int argc, char* argv[]) { 168 | //check command line configs 169 | int opt=0; 170 | opt = getopt( argc, argv, optString ); 171 | while( opt != -1 ) { 172 | switch( opt ) { 173 | case 'b': 174 | if(optarg && !bool(atoi(optarg))) 175 | filler = "\""; 176 | else 177 | filler = "\"FILLER FILL "; 178 | break; 179 | case 'c': 180 | if(optarg && !bool(atoi(optarg))) 181 | continuous = false; 182 | else 183 | continuous = true; 184 | break; 185 | case 'd': 186 | duration = string(optarg); 187 | break; 188 | case 'D': 189 | recordHW = string(optarg); 190 | differentHW = true; 191 | break; 192 | case 'p': 193 | passthrough = true; 194 | break; 195 | case 'I': 196 | forced_input = string(optarg); 197 | break; 198 | case 'v': 199 | if(optarg && !bool(atoi(optarg))) 200 | verify = false; 201 | else 202 | verify = true; 203 | break; 204 | case 'e': 205 | edit = true; 206 | break; 207 | case 'i': 208 | if(optarg && !bool(atoi(optarg))) 209 | ignoreOthers = false; 210 | else 211 | ignoreOthers = true; 212 | break; 213 | case 'q': 214 | if(optarg && !bool(atoi(optarg))) 215 | quiet = false; 216 | else 217 | quiet = true; 218 | break; 219 | case 'l': 220 | command_duration = string(optarg); 221 | break; 222 | case 's': 223 | Setup(); 224 | exit(0); 225 | case 't': 226 | thresh = atof(optarg); 227 | break; 228 | case 'k': 229 | continuous = true; 230 | verify = true; 231 | keyword = string(optarg); 232 | break; 233 | case 'r': 234 | response = string(optarg); 235 | break; 236 | case 'h': 237 | case '?': 238 | DisplayUsage(); 239 | break; 240 | default: 241 | break; 242 | } 243 | opt = getopt( argc, argv, optString ); 244 | } 245 | } 246 | 247 | void VoiceCommand::DisplayUsage() { 248 | //behold my laziness 249 | system("man voicecommand"); 250 | exit(0); 251 | } 252 | 253 | VoiceCommand::VoiceCommand() { 254 | hcurl = NULL; 255 | debug = 0; 256 | //Below are my default values if not changed by user 257 | thresh = 0.7f; 258 | keyword = "pi"; 259 | response = "Yes sir?"; 260 | improper = "Received improper command"; 261 | lang="en"; 262 | quiet = false; 263 | filler = "\"FILLER FILL "; 264 | continuous = false; 265 | verify = false; 266 | edit = false; 267 | ignoreOthers = false; 268 | differentHW = false; 269 | passthrough = false; 270 | recordHW = "plughw:1,0"; 271 | pid_file.clear(); 272 | api.clear(); 273 | forced_input.clear(); 274 | duration = DURATION_DEFAULT; 275 | command_duration = COM_DURATION_DEFAULT; 276 | maxResponse = -1; 277 | char *passPath = getenv("HOME"); 278 | if(passPath == NULL) { 279 | printf("Could not get $HOME\n"); 280 | exit(-1); 281 | } 282 | config_file = string(passPath); 283 | config_file += "/.commands.conf"; 284 | } 285 | 286 | VoiceCommand::~VoiceCommand() { 287 | if (hcurl) curl_easy_cleanup(hcurl); 288 | } 289 | 290 | 291 | inline void VoiceCommand::ProcessMessage(const char* message) { 292 | unsigned int i = 0, loc = 0; 293 | string tmp = message; 294 | string sTmp = message; 295 | to_upper(sTmp); 296 | while(i < voice.size()) { 297 | loc = sTmp.find(voice[i]); 298 | if(loc == 0) { 299 | tmp = commands[i]; 300 | loc = tmp.find("..."); 301 | if(loc != string::npos) { 302 | //Found ... Initiating special options 303 | string newcommand = tmp.substr(0,loc-1); 304 | string options = message; 305 | newcommand += options.substr(voice[i].length()); 306 | if(passthrough) 307 | printf("%s",newcommand.c_str()); 308 | else { 309 | printf("command: %s\n",newcommand.c_str()); 310 | system(newcommand.c_str()); 311 | } 312 | } else { 313 | if(passthrough) 314 | printf("%s",tmp.c_str()); 315 | else { 316 | printf("command: %s\n",tmp.c_str()); 317 | system(tmp.c_str()); 318 | } 319 | } 320 | return; 321 | } else if( voice[i][0] == '~' ) { 322 | // see whether the voice keyword is *anywhere* in the message 323 | string v = voice[i].substr(1, string::npos); 324 | loc = sTmp.find(v); 325 | //printf("v: %s\tloc: %d\tsTmp: %s\n",v.c_str(),loc,sTmp.c_str()); 326 | if( loc != string::npos && loc != -1) { 327 | // if it does, return 328 | if(passthrough) 329 | printf("%s",commands[i].c_str()); 330 | else { 331 | printf("command: %s\n",commands[i].c_str()); 332 | system(commands[i].c_str()); 333 | } 334 | return; 335 | } 336 | } else { 337 | regex rexp("\\$(\\d+)"); cmatch m; 338 | if(regex_search(voice[i].c_str(), m, rexp)) { 339 | //Found $ Initiating special options 340 | int num_var = m.size() + 1; 341 | //fprintf(stderr, "Found # %d $s, initiating special option\n", num_var); 342 | string match = voice[i]; 343 | for(int j = 1; j <= num_var; j++) { 344 | stringstream replace; 345 | replace << "$"; 346 | replace << j; 347 | replace_all(match,replace.str(),"([^\t\n]+?)"); 348 | } 349 | regex rexp2(match); cmatch n; 350 | //this line is the bug somehow (I think) 351 | if(regex_search(sTmp.c_str(), n, rexp2)) { 352 | string run = commands[i]; 353 | for(int j = 0; j <= num_var; j++) { 354 | //fprintf(stderr, "Found %s, initiating special option stage2\n",string(n[j]).c_str()); 355 | stringstream replace; 356 | replace << "$"; 357 | replace << j; 358 | replace_all(run, replace.str(), string(n[j])); 359 | } 360 | if(passthrough) 361 | printf("%s",run.c_str()); 362 | else { 363 | printf("command: %s\n",run.c_str()); 364 | system(run.c_str()); 365 | } 366 | return; 367 | } 368 | } 369 | } 370 | ++i; 371 | } 372 | string improper_tmp = improper + ": " + message + "\n"; 373 | if(ignoreOthers) { 374 | fprintf(stderr,improper_tmp.c_str()); 375 | Speak(improper); 376 | return; 377 | } 378 | string checkit = string(message); 379 | if(message != NULL && !checkit.empty()) { 380 | fprintf(stderr,"Attempting to answer: %s\n",message); 381 | Init(); 382 | Search(message); 383 | } else if(!passthrough) { 384 | printf("No translation\n"); 385 | Speak("No translation"); 386 | } 387 | } 388 | 389 | void VoiceCommand::GetConfig() { 390 | fprintf(stderr,"Opening config file...\n"); 391 | ifstream file(config_file.c_str(),ios::in); 392 | if(!file.is_open()) { 393 | printf("Can't find config file!\nI'll make one.\n"); 394 | EditConfig(); 395 | exit(0); 396 | } 397 | string line; 398 | int i = 1; 399 | while(getline(file, line)) { 400 | unsigned int loc = line.find("=="); 401 | if(line[0] == '!') { 402 | //This is a special config option 403 | //Valid options are keyword==word,continuous==#,verify==#,ignore==#,quiet==#,thresh==#f,response==word improper==word. 404 | string tmp = line.substr(0,6); 405 | if(tmp.compare("!api==") == 0) 406 | api = line.substr(6); 407 | tmp = line.substr(0,7); 408 | if(tmp.compare("!lang==") == 0) 409 | lang = line.substr(7); 410 | tmp = line.substr(0,8); 411 | if(tmp.compare("!quiet==") == 0) 412 | quiet = bool(atoi(line.substr(8).c_str())); 413 | tmp = line.substr(0,9); 414 | if(tmp.compare("!verify==") == 0) 415 | verify = bool(atoi(line.substr(9).c_str())); 416 | if(tmp.compare("!ignore==") == 0) 417 | ignoreOthers = bool(atoi(line.substr(9).c_str())); 418 | if(tmp.compare("!thresh==") == 0) 419 | thresh = atof(line.substr(9).c_str()); 420 | if(tmp.compare("!filler==") == 0) { 421 | filler = line.substr(9); 422 | if(filler.compare("1") == 0) 423 | filler = "\"FILLER FILL "; 424 | else if(filler.compare("0") == 0) 425 | filler = "\""; 426 | else 427 | filler = "\"" + filler; 428 | } 429 | tmp = line.substr(0,10); 430 | if(tmp.compare("!keyword==") == 0) 431 | keyword = line.substr(10); 432 | if(tmp.compare("!com_dur==") == 0) 433 | command_duration = line.substr(10); 434 | if(tmp.compare("!pidfile==") == 0) 435 | pid_file = line.substr(10); 436 | tmp = line.substr(0,11); 437 | if(tmp.compare("!response==") == 0) 438 | response = line.substr(11); 439 | if(tmp.compare("!improper==") == 0) 440 | improper = line.substr(11); 441 | if(tmp.compare("!hardware==") == 0) { 442 | recordHW = line.substr(11); 443 | differentHW = true; 444 | } 445 | if(tmp.compare("!language==") == 0) 446 | lang = line.substr(11); 447 | if(tmp.compare("!duration==") == 0) 448 | duration = line.substr(11); 449 | tmp = line.substr(0,13); 450 | if(tmp.compare("!continuous==") == 0) 451 | continuous = bool(atoi(line.substr(13).c_str())); 452 | tmp = line.substr(0,14); 453 | if(tmp.compare("!maxResponse==") == 0) { 454 | maxResponse = atoi(line.substr(14).c_str()); 455 | if (maxResponse < 1) 456 | maxResponse = -1; 457 | } 458 | } else if(loc < 500 && loc != string::npos && line[0] != '#') { 459 | //This isn't a comment and is formatted properly 460 | string v = line.substr(0,loc); 461 | string c = line.substr(loc + 2); 462 | to_upper(v); 463 | voice.push_back(v); 464 | commands.push_back(c); 465 | } else if(line[0] != '#') { 466 | printf("You have a formatting error on line %d of your config file. I'm ignoring that line\n",i); 467 | } 468 | ++i; 469 | } 470 | file.close(); 471 | } 472 | 473 | void VoiceCommand::EditConfig() { 474 | printf("Editing config file...\n" 475 | "This lets you edit the config file.\nThe format is voice==command\nYou can use any character except for newlines or ==\n" 476 | "If the voice starts with ~, the program looks for the keyword anywhere. Ex: ~weather would pick up on weather or what's the weather\n" 477 | "You can use ... at the end of the command to specify that everything after the given keyword should be options to the command.\n" 478 | "Ex: play==playvideo ...\nThis means that if you say \"play Futurama\", it will run the command playvideo Futurama\n" 479 | "You can use $# (where # is any number 1 to 9) to represent a variable. These should go in order from 1 to 9\n" 480 | "Ex: $1 season $2 episode $3==playvideo -s $2 -e $3 $1\n" 481 | "This means if you say game of thrones season 1 episode 2, it will run playvideo with the -s flag as 1, the -e flag as 2, and the main argument as game of thrones, i.e. playvideo -s 1 -e 2 game of thrones\n" 482 | "Because of these options, it is important that the arguments range from most strict to least strict." 483 | "This means that ~ arguments should probably be at the end.\n" 484 | "arguments with multiple variables like the play $1 season $2 episode $3 example should be before ones like play... because it will pick the first match\n" 485 | "You can also put comments if the line starts with # and options if the line starts with a !\nDefault options are shown as follows:\n" 486 | "!keyword==pi,!verify==1,!continuous==1,!quiet==0,!ignore==0,!thresh=0.7,!response=Yes sir?, !improper=Received improper command:,!duration==3,!com_dur==2,!filler==FILLER FILL,!api==BLANK,!maxResponse==-1," 487 | "!lang==en,!hardware==plughw:1,0\n" 488 | "Press any key to continue\n"); 489 | getchar(); 490 | string edit_command = "nano "; 491 | edit_command += config_file; 492 | system(edit_command.c_str()); 493 | } 494 | 495 | void VoiceCommand::CheckConfig() { 496 | printf("Commands: \n"); 497 | if(voice.size() > 0) { 498 | for(unsigned int i = 0; i < voice.size(); i++) { 499 | printf("%s==%s\n",voice[i].c_str(),commands[i].c_str()); 500 | } 501 | } 502 | } 503 | 504 | int VoiceCommand::Init(void) { 505 | hcurl = curl_easy_init(); 506 | if (!hcurl) return -1; 507 | curl_easy_setopt(hcurl, CURLOPT_ERRORBUFFER, errorbuf); 508 | curl_easy_setopt(hcurl, CURLOPT_WRITEFUNCTION, CurlWriter); 509 | curl_easy_setopt(hcurl, CURLOPT_WRITEDATA, &curlbuf); 510 | 511 | curl_easy_setopt(hcurl, CURLOPT_HEADER, 0); 512 | curl_easy_setopt(hcurl, CURLOPT_FOLLOWLOCATION, 1); 513 | curl_easy_setopt(hcurl, CURLOPT_USERAGENT, "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.8) Gecko/20100804 Gentoo Firefox/3.6.8"); 514 | init = true; 515 | //curl_easy_setopt(hcurl, CURLOPT_COOKIEJAR, "cookie.txt"); 516 | return 0; 517 | } 518 | 519 | int VoiceCommand::CurlWriter(char *data, size_t size, size_t nmemb, string *buffer) { 520 | if (buffer != NULL) { 521 | buffer->append(data, size * nmemb); 522 | return size*nmemb; 523 | } 524 | return 0; 525 | } 526 | 527 | int VoiceCommand::Speak(string message) { 528 | if (quiet) { 529 | return 0; 530 | } 531 | 532 | string command = "tts -l " + lang + " " + filler; 533 | 534 | command += message; 535 | command += "\" 2>>/dev/shm/voice.log 1>>/dev/shm/voice.log"; 536 | system(command.c_str()); 537 | 538 | return 0; 539 | } 540 | 541 | string from_html_entities(string src) 542 | { 543 | struct lookup_s 544 | { 545 | const string from; 546 | const string to; 547 | }; 548 | 549 | static const struct lookup_s conv[] = 550 | { 551 | {""", "\""}, 552 | {""", "\""}, 553 | {""", "\""}, 554 | {"&", "&"}, 555 | {"&", "&"}, 556 | {"&", "&"}, 557 | {"'", "'"}, 558 | {"'", "'"}, 559 | {"'", "'"}, 560 | {"<", "<"}, 561 | {"<", "<"}, 562 | {"<", "<"}, 563 | {">", ">"}, 564 | {">", ">"}, 565 | {">", ">"}, 566 | {"", ""} 567 | }; 568 | 569 | int i; 570 | 571 | for (i = 0; !conv[i].from.empty(); ++i) { 572 | replace_all(src, conv[i].from, conv[i].to); 573 | } 574 | 575 | return (src); 576 | } 577 | 578 | int VoiceCommand::Search(const char* search) { 579 | if(!init) 580 | Init(); 581 | //technically this should never happen now. 582 | if (!hcurl) { 583 | cout << "hcurl is NULL. Did you forget to call Init()?\n"; 584 | return -1; 585 | } 586 | 587 | if(api.empty()) { 588 | string link = "https://www.wolframalpha.com/input/?i="; 589 | link += search; 590 | replace_all(link, string(" "), string("%20")); 591 | //printf("link: %s\n",link.c_str()); 592 | curl_easy_setopt(hcurl, CURLOPT_URL, link.c_str()); 593 | curlbuf.clear(); 594 | cr = curl_easy_perform(hcurl); 595 | if (cr != CURLE_OK) { 596 | cout << "curl() error on getting link: " << errorbuf << endl; 597 | return -3; 598 | } 599 | 600 | if (debug & 2) cout << "\nLink curlbuf: [" << curlbuf << "]\n"; 601 | 602 | regex rexp("0200\\.push\\( \\{\"stringified\": \"(.+?)\",\""); 603 | cmatch m; 604 | if (regex_search(curlbuf.c_str(), m, rexp)) { 605 | string t = string(m[1]); 606 | replace_all(t,"\\n",". \n"); 607 | printf("%s\n", t.c_str()); 608 | Speak(t); 609 | return 0; 610 | } else { 611 | printf("Could not find answer. Try again.\n"); 612 | Speak("Could not find answer. Try again"); 613 | return -1; 614 | } 615 | } else { 616 | string link = "http://api.wolframalpha.com/v2/query?appid="; 617 | link += api; 618 | link += "&reinsterpret=true&translation=true&format=plaintext&input="; 619 | char *curllink = curl_easy_escape(hcurl, search, 0); 620 | link += curllink; 621 | curl_free(curllink); 622 | //printf("link: %s\n",link.c_str()); 623 | curl_easy_setopt(hcurl, CURLOPT_URL, link.c_str()); 624 | curlbuf.clear(); 625 | cr = curl_easy_perform(hcurl); 626 | if (cr != CURLE_OK) { 627 | cout << "curl() error on getting link: " << errorbuf << endl; 628 | return -3; 629 | } 630 | 631 | if (debug & 2) cout << "\nLink curlbuf: [" << curlbuf << "]\n"; 632 | 633 | if (1) { 634 | using boost::property_tree::ptree; 635 | ptree pt; 636 | stringstream ss; 637 | ss << string(curlbuf); 638 | read_xml(ss, pt); 639 | string result = ""; 640 | string plain; 641 | int limit = maxResponse; 642 | BOOST_FOREACH( ptree::value_type const& v, pt.get_child("queryresult") ) { 643 | if (v.first == "pod") { 644 | string title = v.second.get(".title"); 645 | BOOST_FOREACH( ptree::value_type const& v2, v.second.get_child("subpod") ) { 646 | if (limit != 0 && v2.first == "plaintext") { 647 | plain = v2.second.data(); 648 | if (!plain.empty()) { 649 | if (title == "Input interpretation" || title == "Input") { 650 | printf("%s : %s\n", title.c_str(), plain.c_str()); 651 | } else { 652 | if (title != "Response") { 653 | result += title + " : "; 654 | } 655 | result += plain + "\n"; 656 | limit--; 657 | } 658 | } 659 | } 660 | } 661 | } 662 | } 663 | if (result.empty()) { 664 | BOOST_FOREACH( ptree::value_type const& v, pt.get_child("queryresult") ) { 665 | if (v.first == "didyoumeans") { 666 | result = v.second.get("didyoumean"); 667 | printf("No luck, will try with %s\n", result.c_str()); 668 | return Search(result.c_str()); 669 | } 670 | } 671 | printf("Could not find answer. Try again.\n"); 672 | Speak("Could not find answer. Try again"); 673 | } else { 674 | result = from_html_entities(result); 675 | printf("%s\n", result.c_str()); 676 | Speak(result); 677 | return 0; 678 | } 679 | } else { 680 | regex rexp("([^<].+?)</plaintext>"); 681 | smatch m; 682 | string::const_iterator endbuf = curlbuf.end(); 683 | if (regex_search(curlbuf, m, rexp) 684 | && regex_search(m[1].second, endbuf, m, rexp)) { 685 | //char * curlrep = curl_easy_unescape(hcurl, m.str(1).c_str(), 0, NULL); 686 | //string t = string(curlrep); 687 | //curl_free(curlrep); 688 | string t = string(m.str(1)); 689 | t = from_html_entities(t); 690 | printf("%s\n", t.c_str()); 691 | Speak(t); 692 | return 0; 693 | } else { 694 | regex rexp2("<didyoumean [^>]*?>(.+?)</didyoumean>"); 695 | cmatch m2; 696 | if (regex_search(curlbuf.c_str(), m2, rexp2)) { 697 | printf("No luck, will try with %s\n", m2.str(1).c_str()); 698 | return Search(m2.str(1).c_str()); 699 | } 700 | 701 | printf("Could not find answer. Try again.\n"); 702 | Speak("Could not find answer. Try again"); 703 | return -1; 704 | } 705 | } 706 | } 707 | return 0; 708 | } 709 | 710 | void changemode(int dir) 711 | { 712 | static struct termios oldt, newt; 713 | 714 | if ( dir == 1 ) 715 | { 716 | tcgetattr( STDIN_FILENO, &oldt); 717 | newt = oldt; 718 | newt.c_lflag &= ~( ICANON | ECHO ); 719 | tcsetattr( STDIN_FILENO, TCSANOW, &newt); 720 | } 721 | else 722 | tcsetattr( STDIN_FILENO, TCSANOW, &oldt); 723 | } 724 | 725 | int kbhit (void) 726 | { 727 | struct timeval tv; 728 | fd_set rdfs; 729 | 730 | tv.tv_sec = 0; 731 | tv.tv_usec = 0; 732 | 733 | FD_ZERO(&rdfs); 734 | FD_SET (STDIN_FILENO, &rdfs); 735 | 736 | select(STDIN_FILENO+1, &rdfs, NULL, NULL, &tv); 737 | return FD_ISSET(STDIN_FILENO, &rdfs); 738 | 739 | } 740 | 741 | void VoiceCommand::Setup() { 742 | //Function in order to detect your default options. 743 | //It will then set these automatically in the config file. 744 | bool change=false; 745 | char buffer[100]; 746 | string write = ""; 747 | printf("Do you want to permanently set the continuous flag so that it always runs continuously? (y/n)\n"); 748 | scanf("%s",buffer); 749 | if(buffer[0] == 'y') { 750 | continuous = true; 751 | write += "!continuous==1\n"; 752 | } 753 | printf("Do you want to permanently set the verify flag so that it always verifies the keyword? (y/n)\n"); 754 | scanf("%s",buffer); 755 | if(buffer[0] == 'y') { 756 | verify = true; 757 | write += "!verify==1\n"; 758 | } 759 | printf("Do you want to permanently set the ignore flag so that it never looks for answers outside the config file? (y/n)\n"); 760 | scanf("%s",buffer); 761 | if(buffer[0] == 'y') { 762 | ignoreOthers = true; 763 | write += "!ignore==1\n"; 764 | } 765 | printf("Do you want to permanently set the quiet flag so that it never uses audio out to speak? (y/n)\n"); 766 | scanf("%s",buffer); 767 | if(buffer[0] == 'y') { 768 | quiet = true; 769 | write += "!quiet==1\n"; 770 | } 771 | printf("Do you want to permanently change the default duration of the speech recognition (3 seconds)? (y/n)\n"); 772 | scanf("%s",buffer); 773 | if(buffer[0] == 'y') { 774 | printf("Type the number of seconds you want it to run: ex 3\n"); 775 | int num; 776 | scanf("%d", &num); 777 | write += "!duration=="; 778 | stringstream tmp; 779 | tmp << num; 780 | duration = tmp.str(); 781 | write += duration; 782 | write += "\n"; 783 | } 784 | printf("Do you want to permanently change the default command duration of the speech recognition (2 seconds)? (y/n)\n"); 785 | scanf("%s",buffer); 786 | if(buffer[0] == 'y') { 787 | printf("Type the number of seconds you want it to run: ex 2\n"); 788 | int num; 789 | scanf("%d", &num); 790 | write += "!com_dur=="; 791 | stringstream tmp; 792 | tmp << num; 793 | command_duration = tmp.str(); 794 | write += command_duration; 795 | write += "\n"; 796 | } 797 | 798 | //Now we will check some more options and check the TTS and speech recognition 799 | printf("Do you want to set up and check the text to speech options? (y/n)\n"); 800 | scanf("%s",buffer); 801 | if(buffer[0] == 'y') { 802 | printf("First I'm going to say something and see if you hear it\n"); 803 | system("tts \"FILLER FILL This program was created by Steven Hickson\""); 804 | printf("Did you hear anything? (y/n)\n"); 805 | scanf("%s",buffer); 806 | if(buffer[0] == 'n') { 807 | printf("Something went wrong and you should run the install script and install the dependecies as well\n"); 808 | printf("You might also want to change some alsa options using alsamixer and alsa force-reload\n"); 809 | exit(-1); 810 | } 811 | printf("\nIf you heard the word FILL (or FILLER or FILLER FILL) at the beginning of the sentence, the filler flag should be set to 0 or be blank\n"); 812 | printf("Do you want me to permanently set the filler flag to 0? (y/n)\n"); 813 | scanf("%s",buffer); 814 | if(buffer[0] == 'y') { 815 | filler = "\""; 816 | write += "!filler==0\n"; 817 | } 818 | string cmd; 819 | printf("\nThe default response of the system after it finds the keyword is \"Yes Sir?\"\n"); 820 | printf("Do you want to change the response? (y/n)\n"); 821 | change = false; 822 | scanf("%s",buffer); 823 | if(buffer[0] == 'y') { 824 | change = true; 825 | while(change) { 826 | printf("Type the phrase you want as the response:\n"); 827 | scanf("%s",buffer); 828 | cmd = "tts " + filler; 829 | cmd += string(buffer); 830 | cmd += "\""; 831 | system(cmd.c_str()); 832 | response = string(buffer); 833 | printf("Did that sound correct? (y/n)\n"); 834 | scanf("%s",buffer); 835 | if(buffer[0] == 'y') 836 | change = false; 837 | } 838 | write += "!response=="; 839 | write += response; 840 | write += "\n"; 841 | } 842 | printf("\nThe default response of the system after it receives an unknown command is \"Received improper command:\"\n"); 843 | printf("Do you want to change the response? (y/n)\n"); 844 | change = false; 845 | scanf("%s",buffer); 846 | if(buffer[0] == 'y') { 847 | change = true; 848 | while(change) { 849 | printf("Type the phrase you want as the 'command not found' response:\n"); 850 | scanf("%s",buffer); 851 | cmd = "tts " + filler; 852 | cmd += string(buffer); 853 | cmd += "\""; 854 | system(cmd.c_str()); 855 | improper = string(buffer); 856 | printf("Did that sound correct? (y/n)\n"); 857 | scanf("%s",buffer); 858 | if(buffer[0] == 'y') 859 | change = false; 860 | } 861 | write += "!improper=="; 862 | write += improper; 863 | write += "\n"; 864 | } 865 | } 866 | 867 | //Now we will check some more options and check the TTS and speech recognition 868 | printf("Do you want to set up and check the speech recognition options? (y/n)\n"); 869 | scanf("%s",buffer); 870 | if(buffer[0] == 'y') { 871 | printf("First I'm going to make sure you have the correct hardware device\n"); 872 | FILE *cmd; 873 | int card = -1,device = -1; 874 | cmd = popen("arecord -l | awk '/^card [0-9]/ {print $2}'","r"); 875 | fscanf(cmd, "%d:",&card); 876 | cmd = popen("arecord -l | grep -o 'device [0-9]:' | grep -o '[0-9]:'","r"); 877 | fscanf(cmd, "%d:",&device); 878 | if(card == -1 || device == -1) { 879 | printf("I couldn't find a hardware device. You don't have a valid microphone\n"); 880 | exit(-1); 881 | } else if(card != 1 || device != 0) { 882 | printf("I detected that you have a different audio card then I located, would you like me to fix that in the config file? (y/n)\n"); 883 | scanf("%s",buffer); 884 | if(buffer[0] == 'y') { 885 | stringstream tmp; 886 | tmp << "plughw:"; 887 | tmp << card; 888 | tmp << ","; 889 | tmp << device; 890 | recordHW = tmp.str(); 891 | differentHW = true; 892 | write += "!hardware=="; 893 | write += recordHW; 894 | write += "\n"; 895 | } 896 | } else 897 | printf("Everything seems right with the hardware config\n"); 898 | printf("\nWould you like me to try to get the proper audio threshold? (y/n)\n"); 899 | scanf("%s",buffer); 900 | if(buffer[0] == 'y') { 901 | float low, high; 902 | printf("I'm going to record you once while you are silent and then once while you say the command in order to determine the threshold\n"); 903 | printf("Getting ready for silent recording, just don't say anything while this is happening, press any key when ready\n"); 904 | getchar(); 905 | getchar(); //Needed it twice here for whatever reason 906 | low = GetVolume(recordHW, command_duration, false); 907 | printf("Getting ready for command recording, try saying the command while this is happening, press any key when ready\n"); 908 | getchar(); 909 | high = GetVolume(recordHW, command_duration, false); 910 | float tmp = (high - low) * 0.75f + low; 911 | if(tmp != thresh) { 912 | printf("I detected that your default thresh: %f is different than the thresh I detected that you should use: %f\n",thresh,tmp); 913 | printf("Should I set that in the config file? (y/n)\n"); 914 | scanf("%s",buffer); 915 | if(buffer[0] == 'y') { 916 | thresh = tmp; 917 | stringstream convert; 918 | convert << thresh; 919 | write += "!thresh=="; 920 | write += convert.str(); 921 | write += "\n"; 922 | } 923 | } 924 | } 925 | printf("\nThe default keyword of the system is \"pi\"\n"); 926 | printf("Do you want to change the keyword? (y/n)\n"); 927 | change = false; 928 | scanf("%s",buffer); 929 | if(buffer[0] == 'y') { 930 | change = true; 931 | FILE *cmd; 932 | while(change) { 933 | printf("Type the phrase you want as the keyword:\n"); 934 | scanf("%s",buffer); 935 | keyword = string(buffer); 936 | char message[200]; 937 | printf("Now say that keyword\n"); 938 | string command = "speech-recog.sh"; 939 | if(differentHW) { 940 | command += " -D "; 941 | command += recordHW; 942 | } 943 | command += " -d "; 944 | command += duration; 945 | cmd = popen(command.c_str(),"r"); 946 | fscanf(cmd,"\"%[^\"\n]\"\n",message); 947 | if(iequals(message,keyword.c_str())) 948 | printf("I got %s, which was a perfect match!\n",message); 949 | else 950 | printf("I got %s, which was different than what you typed: %s\n",message,keyword.c_str()); 951 | printf("Did that seem correct? (y/n)\n"); 952 | scanf("%s",buffer); 953 | if(buffer[0] == 'y') 954 | change = false; 955 | } 956 | write += "!keyword=="; 957 | write += keyword; 958 | write += "\n"; 959 | } 960 | } 961 | 962 | //Now we will write everything to the config file 963 | string tmp = "echo \""; 964 | tmp += write; 965 | tmp += "\" >> "; 966 | tmp += config_file; 967 | //I am doing it this way because I'm lazy 968 | system(tmp.c_str()); 969 | printf("Done setting everything up!\n"); 970 | } 971 | --------------------------------------------------------------------------------