Skip to content

Commit

Permalink
search: remove google functionality, alias .g to .ddg
Browse files Browse the repository at this point in the history
Google removed their deprecated API we used for searching.
Since their new API requires API keys (and sometimes money), it's
simply not worth the hassle to support. Duck Duck Go should be good
enough.

This fixes issue #650, in a way.
  • Loading branch information
Elad Alfassa committed Dec 19, 2014
1 parent 56f25ea commit 75854a6
Showing 1 changed file with 10 additions and 103 deletions.
113 changes: 10 additions & 103 deletions willie/modules/search.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,100 +17,13 @@
import time


def google_ajax(query):
"""Search using AjaxSearch, and return its JSON."""
uri = 'http://ajax.googleapis.com/ajax/services/search/web'
args = '?v=1.0&safe=off&q=' + query
bytes = web.get(uri + args)
return json.loads(bytes)


def google_search(query):
results = google_ajax(query)
try:
return results['responseData']['results'][0]['unescapedUrl']
except IndexError:
return None
except TypeError:
return False


def google_count(query):
results = google_ajax(query)
if not 'responseData' in results:
return '0'
if not 'cursor' in results['responseData']:
return '0'
if not 'estimatedResultCount' in results['responseData']['cursor']:
return '0'
return results['responseData']['cursor']['estimatedResultCount']


def formatnumber(n):
"""Format a number with beautiful commas."""
parts = list(str(n))
for i in range((len(parts) - 3), 0, -3):
parts.insert(i, ',')
return ''.join(parts)


@commands('g', 'google')
@example('.g swhack')
def g(bot, trigger):
"""Queries Google for the specified input."""
query = trigger.group(2)
if not query:
return bot.reply('.g what?')
uri = google_search(query)
if uri:
bot.reply(uri)
if 'last_seen_url' in bot.memory:
bot.memory['last_seen_url'][trigger.sender] = uri
elif uri is False:
bot.reply("Problem getting data from Google.")
else:
bot.reply("No results found for '%s'." % query)


@commands('gc')
@example('.gc extrapolate')
def gc(bot, trigger):
"""Returns the number of Google results for the specified input."""
query = trigger.group(2)
if not query:
return bot.reply('.gc what?')
num = formatnumber(google_count(query))
bot.say(query + ': ' + num)

r_query = re.compile(
r'\+?"[^"\\]*(?:\\.[^"\\]*)*"|\[[^]\\]*(?:\\.[^]\\]*)*\]|\S+'
)


@commands('gcs', 'comp')
@example('.gcs foo bar')
def gcs(bot, trigger):
"""Compare the number of Google search results"""
if not trigger.group(2):
return bot.reply("Nothing to compare.")
queries = r_query.findall(trigger.group(2))
if len(queries) > 6:
return bot.reply('Sorry, can only compare up to six things.')

results = []
for i, query in enumerate(queries):
query = query.strip('[]')
n = int((formatnumber(google_count(query)) or '0').replace(',', ''))
results.append((n, query))
if i >= 2:
time.sleep(0.25)
if i >= 4:
time.sleep(0.25)

results = [(term, n) for (n, term) in reversed(sorted(results))]
reply = ', '.join('%s (%s)' % (t, formatnumber(n)) for (t, n) in results)
bot.say(reply)

r_bing = re.compile(r'<h3><a href="([^"]+)"')


Expand All @@ -134,6 +47,9 @@ def duck_search(query):
if m:
return web.decode(m.group(1))

# Alias google_search to duck_search
google_search = duck_search


def duck_api(query):
if '!bang' in query.lower():
Expand All @@ -147,21 +63,21 @@ def duck_api(query):
return None


@commands('duck', 'ddg')
@commands('duck', 'ddg', 'g')

This comment has been minimized.

Copy link
@tyrope

tyrope Dec 19, 2014

I strongly disagree with the decision to make .g search duck duck go. In my opinion it's false advertising.

This comment has been minimized.

Copy link
@lramati

lramati via email Dec 19, 2014

Contributor

This comment has been minimized.

Copy link
@elad661

elad661 Dec 19, 2014

Contributor

The functionality is similar, so why does it matter?

This comment has been minimized.

Copy link
@lramati

lramati via email Dec 19, 2014

Contributor

This comment has been minimized.

Copy link
@elad661

elad661 Dec 19, 2014

Contributor

I haven't seen a case where it wasn't, and regardless forcing users to retrain to use .ddg explicitly is silly.

This comment has been minimized.

Copy link
@lramati

lramati via email Dec 19, 2014

Contributor

This comment has been minimized.

Copy link
@embolalia

embolalia Dec 19, 2014

Contributor

@tyrope we aren't advertising anything, so saying it's false advertising is false.

I agree with @elad661. .g is primarily "search for something", rather than "search google for something". I think we'll get far more whining by removing it than changing what it uses. Besides, Google searches are not repeatable - "the result from Google" is not a thing, only "the result a specific client was given on a specific machine at a specific time from a specific location with the specific cookies and whatnot it sent". I have, numerous times, repeated a .g search with my web browser, and gotten a different result, because that result is, from a user's perspective, arbitrary. If the user wants clarity into the algorithm used to retrieve that result, they should not be using Google.

If it's really that big a deal, then from now on the G stands for Go.

This comment has been minimized.

Copy link
@embolalia

embolalia Dec 19, 2014

Contributor

Regarding adding a message, that would be unfathomably annoying and, again, Willie will always do the thing that does the most sense to the end user when it is technologically feasible. Printing out a message when you do that search does not accomplish that.

@example('.duck privacy or .duck !mcwiki obsidian')
def duck(bot, trigger):
"""Queries Duck Duck Go for the specified input."""
query = trigger.group(2)
if not query:
return bot.reply('.ddg what?')

#If the API gives us something, say it and stop
# If the API gives us something, say it and stop
result = duck_api(query)
if result:
bot.reply(result)
return

#Otherwise, look it up on the HTMl version
# Otherwise, look it up on the HTMl version
uri = duck_search(query)

if uri:
Expand All @@ -175,30 +91,21 @@ def duck(bot, trigger):
@commands('search')
@example('.search nerdfighter')
def search(bot, trigger):
"""Searches Google, Bing, and Duck Duck Go."""
"""Searches Bing and Duck Duck Go."""
if not trigger.group(2):
return bot.reply('.search for what?')
query = trigger.group(2)
gu = google_search(query) or '-'
bu = bing_search(query) or '-'
du = duck_search(query) or '-'

if (gu == bu) and (bu == du):
result = '%s (g, b, d)' % gu
elif (gu == bu):
result = '%s (g, b), %s (d)' % (gu, du)
elif (bu == du):
result = '%s (b, d), %s (g)' % (bu, gu)
elif (gu == du):
result = '%s (g, d), %s (b)' % (gu, bu)
if bu == du:
result = '%s (b, d)' % gu
else:
if len(gu) > 250:
gu = '(extremely long link)'
if len(bu) > 150:
bu = '(extremely long link)'
if len(du) > 150:
du = '(extremely long link)'
result = '%s (g), %s (b), %s (d)' % (gu, bu, du)
result = '%s (b), %s (d)' % (bu, du)

bot.reply(result)

Expand Down

0 comments on commit 75854a6

Please sign in to comment.