1 module SeekingWhirl;
2 import std.conv;
3 import std.json;
4 import std.net.curl;
5 /**
6 	* DuckDuckGo API for D
7 	* Authors: Azbuka-slovensko
8 	* License: MIT
9 */
10 class SeekingWhirl {
11 	///topic summary (can contain HTML)
12 	string Abstract;
13 	///topic summary (w\o HTML)
14 	string AbstractText;
15 	///name of source
16 	string AbstractSource;
17 	///link to topic page
18 	string AbstractURL;
19 	///link to Abstract's image
20 	string Image;
21 	///Abstract's topic name
22 	string Heading;
23 	
24 	///instant answer
25 	string Answer;
26 	///instant answer type
27 	string AnswerType;
28 	
29 	///dictionary Definition
30 	string Definition;
31 	///name of Definition source
32 	string DefinitionSource;
33 	///link to expanded page
34 	string DefinitionURL;
35 	
36 	///icon asociated with topic
37 	struct icon {
38 		///link to icon
39 		string URL;
40 		///icon height
41 		long Height;
42 		///icon width
43 		long Width;
44 	}
45 	
46 	///external links
47 	struct result {
48 		///link to topic
49 		string Result;
50 		///first url in Result
51 		string FirstURL;
52 		///icon of topic
53 		icon Icon;
54 		///text from firstURL
55 		string Text;
56 	}
57 	
58 	///array of internal links
59 	result[] RelatedTopics;
60 	///array of external links
61 	result[] Results;
62 	
63 	///response category
64 	string Type;
65 	///!bang redirect
66 	string Redirect;
67 	
68 	
69 	/**
70 		* Search
71 		* Params:
72 		*	query = string to search
73 		*	appname = name of app
74 		*	no_redirect = true to skip HTTP redirects
75 		*	no_html = true to remove HTML from text
76 		*	skip_disambig = true to skip disambugation (D) Type
77 	*/
78 	this(string query,
79 		string appname = "",
80 		bool no_redirect = false,
81 		bool no_html = false,
82 		bool skip_disambig = false) {
83 		string url = "http://api.duckduckgo.com/?q=" ~ query
84 			~ "&format=json";
85 		if(appname)
86 			url ~= "&t=" ~ appname;
87 		if(no_redirect)
88 			url ~= "&no_redirect=1";
89 		if(no_html)
90 			url ~= "&no_html=1";
91 		if(skip_disambig)
92 			url ~= "&skip_disambig=1";
93 			
94 		JSONValue j = parseJSON(get(url));
95 		
96 		this.Abstract = j["Abstract"].str;
97 		this.AbstractText = j["AbstractText"].str;
98 		this.AbstractSource = j["AbstractSource"].str;
99 		this.AbstractURL = j["AbstractURL"].str;
100 		this.Image = j["Image"].str;
101 		this.Heading = j["Heading"].str;
102 		
103 		this.Answer = j["Answer"].str;
104 		this.AnswerType = j["AnswerType"].str;
105 		
106 		this.Definition = j["Definition"].str;
107 		this.DefinitionSource = j["DefinitionSource"].str;
108 		this.DefinitionURL = j["DefinitionURL"].str;
109 		
110 		try {
111 			for(ulong i = 0; i < j["RelatedTopics"].array.length; i++) {
112 				this.RelatedTopics ~= result(j["RelatedTopics"][i]["Result"].str,
113 					j["RelatedTopics"][i]["FirstURL"].str,
114 					icon(j["RelatedTopics"][i]["Icon"]["URL"].str,
115 						DDGNumber(j["RelatedTopics"][i]["Icon"]["Height"]),
116 						DDGNumber(j["RelatedTopics"][i]["Icon"]["Width"])
117 					),
118 					j["RelatedTopics"][i]["Text"].str
119 				);
120 			}
121 		} catch { }
122 		try {
123 			for(ulong i = 0; i < j["Results"].array.length; i++) {
124 				this.Results ~= result(j["Results"][i]["Result"].str,
125 					j["Results"][i]["FirstURL"].str,
126 					icon(j["Results"][i]["Icon"]["URL"].str,
127 						DDGNumber(j["Results"][i]["Icon"]["Height"]),
128 						DDGNumber(j["Results"][i]["Icon"]["Width"])
129 					),
130 					j["Results"][i]["Text"].str
131 				);
132 			}
133 		} catch { }
134 	}
135 	private long DDGNumber(JSONValue j) {
136 		try {
137 			return j.integer;
138 		} catch {
139 			return 0;
140 		}
141 		
142 	}
143 }