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